From 884d3ea4d8662b7ba3a17f75906d217d457aba08 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Tue, 8 Jan 2013 06:19:05 -0400 Subject: [PATCH 001/817] Rip out OIS, fill the holes with SDL goodness. WIP. --- CMakeLists.txt | 8 +- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/mwinput/inputmanagerimp.cpp | 155 ++++++----- apps/openmw/mwinput/inputmanagerimp.hpp | 36 ++- apps/openmw/mwinput/sdlinputwrapper.cpp | 70 +++++ apps/openmw/mwinput/sdlinputwrapper.hpp | 35 +++ cmake/FindSDL2.cmake | 180 +++++++++++++ extern/oics/CMakeLists.txt | 1 + extern/oics/ICSInputControlSystem.cpp | 241 +++++++++--------- extern/oics/ICSInputControlSystem.h | 54 ++-- .../oics/ICSInputControlSystem_joystick.cpp | 113 ++++---- .../oics/ICSInputControlSystem_keyboard.cpp | 26 +- extern/oics/ICSInputControlSystem_mouse.cpp | 32 +-- extern/oics/ICSPrerequisites.h | 14 +- extern/oics/OISCompat.h | 90 +++++++ 15 files changed, 722 insertions(+), 336 deletions(-) create mode 100644 apps/openmw/mwinput/sdlinputwrapper.cpp create mode 100644 apps/openmw/mwinput/sdlinputwrapper.hpp create mode 100644 cmake/FindSDL2.cmake create mode 100644 extern/oics/OISCompat.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 766167672..b1eb91d76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,7 +204,7 @@ endif() find_package(OGRE REQUIRED) find_package(MyGUI REQUIRED) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -find_package(OIS REQUIRED) +find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) IF(OGRE_STATIC) @@ -218,7 +218,8 @@ ENDIF(OGRE_STATIC) include_directories("." ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} ${OGRE_Terrain_INCLUDE_DIR} - ${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} + ${SDL2_INCLUDE_DIR} + ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} ${MYGUI_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS} @@ -227,7 +228,7 @@ include_directories("." ${LIBDIR} ) -link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) +link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) if (APPLE) # List used Ogre plugins @@ -361,6 +362,7 @@ if(DPKG_PROGRAM) SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") + #TODO: should SDL2 be mentioned in here somewhere? SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 56147b500..88a05c810 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,7 +20,7 @@ add_openmw_dir (mwrender ) add_openmw_dir (mwinput - inputmanagerimp + inputmanagerimp sdlinputwrapper ) add_openmw_dir (mwgui @@ -103,6 +103,7 @@ target_link_libraries(openmw ${SOUND_INPUT_LIBRARY} ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} + ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} "shiny" "shiny.OgrePlatform" diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 995da8f34..a6f0f64d4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -9,8 +9,6 @@ #include -#include - #include #include #include @@ -25,6 +23,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +using namespace ICS; + namespace MWInput { InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, @@ -59,14 +59,19 @@ namespace MWInput window->getCustomAttribute("WINDOW", &windowHnd); + + // Set non-exclusive mouse and keyboard input if the user requested + // it. + + //TODO: re-enable this and make it work with SDL + /* + std::ostringstream windowHndStr; OIS::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 (debug) { #if defined OIS_WIN32_PLATFORM @@ -89,6 +94,7 @@ namespace MWInput std::string("true"))); #endif } + */ #if defined(__APPLE__) && !defined(__LP64__) // Give the application window focus to receive input events @@ -97,24 +103,17 @@ namespace MWInput SetFrontProcess(&psn); #endif - mInputManager = OIS::InputManager::createInputSystem( pl ); - - // Create all devices - mKeyboard = static_cast(mInputManager->createInputObject - ( OIS::OISKeyboard, true )); - mMouse = static_cast(mInputManager->createInputObject - ( OIS::OISMouse, true )); - - mKeyboard->setEventCallback (this); - mMouse->setEventCallback (this); - - adjustMouseRegion (window->getWidth(), window->getHeight()); - - MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mMouse->getMouseState ().Z.abs); + mInputManager = new MWSDLInputWrapper(window); + mInputManager->setMouseEventCallback (this); + mInputManager->setKeyboardEventCallback (this); std::string file = userFileExists ? userFile : ""; mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); + adjustMouseRegion (window->getWidth(), window->getHeight()); + + MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, 0); + loadKeyDefaults(); for (int i = 0; i < A_Last; ++i) @@ -139,9 +138,7 @@ namespace MWInput delete mInputCtrl; - mInputManager->destroyInputObject(mKeyboard); - mInputManager->destroyInputObject(mMouse); - OIS::InputManager::destroyInputSystem(mInputManager); + delete mInputManager; } void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) @@ -240,8 +237,7 @@ namespace MWInput void InputManager::update(float dt, bool loading) { // Tell OIS to handle all input events - mKeyboard->capture(); - mMouse->capture(); + mInputManager->capture(); // inject some fake mouse movement to force updating MyGUI's widget states // this shouldn't do any harm since we're moving back to the original position afterwards @@ -304,7 +300,7 @@ namespace MWInput if (mControlSwitch["playerviewswitch"]) { // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mKeyboard->isModifierDown (OIS::Keyboard::Alt)) { + if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(KMOD_ALT)) { if (mPreviewPOVDelay <= 0.5 && (mPreviewPOVDelay += dt) > 0.5) { @@ -419,37 +415,38 @@ namespace MWInput void InputManager::adjustMouseRegion(int width, int height) { - const OIS::MouseState &ms = mMouse->getMouseState(); - ms.width = width; - ms.height = height; + mInputCtrl->adjustMouseRegion(width, height); } - bool InputManager::keyPressed( const OIS::KeyEvent &arg ) + bool InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { mInputCtrl->keyPressed (arg); - unsigned int text = arg.text; + unsigned int text = arg.keysym.unicode; + + //TODO: Check if we need this with SDL + /* #ifdef __APPLE__ // filter \016 symbol for F-keys on OS X - if ((arg.key >= OIS::KC_F1 && arg.key <= OIS::KC_F10) || - (arg.key >= OIS::KC_F11 && arg.key <= OIS::KC_F15)) { + if ((arg.key >= SDLK_F1 && arg.key <= SDLK_F10) || + (arg.key >= SDLK_F11 && arg.key <= SDLK_F15)) { text = 0; } #endif - - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.key), text); + */ + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.keysym.sym), text); return true; } - bool InputManager::keyReleased( const OIS::KeyEvent &arg ) + bool InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { mInputCtrl->keyReleased (arg); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key)); + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.keysym.sym)); return true; } - bool InputManager::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) + bool InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { mInputCtrl->mousePressed (arg, id); @@ -467,7 +464,7 @@ namespace MWInput return true; } - bool InputManager::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) + bool InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) { mInputCtrl->mouseReleased (arg, id); @@ -476,7 +473,7 @@ namespace MWInput return true; } - bool InputManager::mouseMoved( const OIS::MouseEvent &arg ) + bool InputManager::mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ) { mInputCtrl->mouseMoved (arg); @@ -488,11 +485,13 @@ namespace MWInput // 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 += float(arg.state.X.rel) * mUISensitivity; - mMouseY += float(arg.state.Y.rel) * mUISensitivity * mUIYMultiplier; + mMouseX += float(arg.xrel) * mUISensitivity; + mMouseY += float(arg.yrel) * mUISensitivity * mUIYMultiplier; mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); - mMouseWheel = arg.state.Z.abs; + + //there's no such thing as an absolute z position, so let's keep track of it ourselves + mMouseWheel += arg.zrel; MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); } @@ -501,8 +500,8 @@ namespace MWInput { resetIdleTime(); - float x = arg.state.X.rel * mCameraSensitivity * 0.2; - float y = arg.state.Y.rel * mCameraSensitivity * 0.2 * (mInvertY ? -1 : 1) * mUIYMultiplier; + float x = arg.xrel * mCameraSensitivity * 0.2; + float y = arg.yrel * mCameraSensitivity * 0.2 * (mInvertY ? -1 : 1) * mUIYMultiplier; MWBase::World *world = MWBase::Environment::get().getWorld(); world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); @@ -679,38 +678,38 @@ namespace MWInput // across different versions of OpenMW (in the case where another input action is added) std::map defaultKeyBindings; - defaultKeyBindings[A_Activate] = OIS::KC_SPACE; - defaultKeyBindings[A_MoveBackward] = OIS::KC_S; - defaultKeyBindings[A_MoveForward] = OIS::KC_W; - defaultKeyBindings[A_MoveLeft] = OIS::KC_A; - defaultKeyBindings[A_MoveRight] = OIS::KC_D; - defaultKeyBindings[A_ToggleWeapon] = OIS::KC_F; - defaultKeyBindings[A_ToggleSpell] = OIS::KC_R; - defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1; - defaultKeyBindings[A_Console] = OIS::KC_F2; - defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL; - defaultKeyBindings[A_AutoMove] = OIS::KC_Q; - defaultKeyBindings[A_Jump] = OIS::KC_E; - defaultKeyBindings[A_Journal] = OIS::KC_J; - defaultKeyBindings[A_Rest] = OIS::KC_T; - defaultKeyBindings[A_GameMenu] = OIS::KC_ESCAPE; - defaultKeyBindings[A_TogglePOV] = OIS::KC_TAB; - defaultKeyBindings[A_QuickKey1] = OIS::KC_1; - defaultKeyBindings[A_QuickKey2] = OIS::KC_2; - defaultKeyBindings[A_QuickKey3] = OIS::KC_3; - defaultKeyBindings[A_QuickKey4] = OIS::KC_4; - defaultKeyBindings[A_QuickKey5] = OIS::KC_5; - defaultKeyBindings[A_QuickKey6] = OIS::KC_6; - defaultKeyBindings[A_QuickKey7] = OIS::KC_7; - defaultKeyBindings[A_QuickKey8] = OIS::KC_8; - defaultKeyBindings[A_QuickKey9] = OIS::KC_9; - defaultKeyBindings[A_QuickKey10] = OIS::KC_0; - defaultKeyBindings[A_Screenshot] = OIS::KC_SYSRQ; - defaultKeyBindings[A_ToggleHUD] = OIS::KC_F12; + defaultKeyBindings[A_Activate] = SDLK_SPACE; + defaultKeyBindings[A_MoveBackward] = SDLK_s; + defaultKeyBindings[A_MoveForward] = SDLK_w; + defaultKeyBindings[A_MoveLeft] = SDLK_a; + defaultKeyBindings[A_MoveRight] = SDLK_d; + defaultKeyBindings[A_ToggleWeapon] = SDLK_f; + defaultKeyBindings[A_ToggleSpell] = SDLK_r; + defaultKeyBindings[A_QuickKeysMenu] = SDLK_F1; + defaultKeyBindings[A_Console] = SDLK_F2; + defaultKeyBindings[A_Crouch] = SDLK_LCTRL; + defaultKeyBindings[A_AutoMove] = SDLK_q; + defaultKeyBindings[A_Jump] = SDLK_e; + defaultKeyBindings[A_Journal] = SDLK_j; + defaultKeyBindings[A_Rest] = SDLK_t; + defaultKeyBindings[A_GameMenu] = SDLK_ESCAPE; + defaultKeyBindings[A_TogglePOV] = SDLK_TAB; + defaultKeyBindings[A_QuickKey1] = SDLK_1; + defaultKeyBindings[A_QuickKey2] = SDLK_2; + defaultKeyBindings[A_QuickKey3] = SDLK_3; + defaultKeyBindings[A_QuickKey4] = SDLK_4; + defaultKeyBindings[A_QuickKey5] = SDLK_5; + defaultKeyBindings[A_QuickKey6] = SDLK_6; + defaultKeyBindings[A_QuickKey7] = SDLK_7; + defaultKeyBindings[A_QuickKey8] = SDLK_8; + defaultKeyBindings[A_QuickKey9] = SDLK_9; + defaultKeyBindings[A_QuickKey10] = SDLK_0; + defaultKeyBindings[A_Screenshot] = SDLK_SYSREQ; + defaultKeyBindings[A_ToggleHUD] = SDLK_F12; std::map defaultMouseButtonBindings; - defaultMouseButtonBindings[A_Inventory] = OIS::MB_Right; - defaultMouseButtonBindings[A_Use] = OIS::MB_Left; + defaultMouseButtonBindings[A_Inventory] = SDL_BUTTON_RIGHT; + defaultMouseButtonBindings[A_Use] = SDL_BUTTON_LEFT; for (int i = 0; i < A_Last; ++i) { @@ -728,14 +727,14 @@ namespace MWInput } if (!controlExists || force || - ( mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) == OIS::KC_UNASSIGNED + ( mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) == SDLK_UNKNOWN && mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { clearAllBindings (control); if (defaultKeyBindings.find(i) != defaultKeyBindings.end()) - mInputCtrl->addKeyBinding(control, static_cast(defaultKeyBindings[i]), ICS::Control::INCREASE); + mInputCtrl->addKeyBinding(control, static_cast(defaultKeyBindings[i]), ICS::Control::INCREASE); else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end()) mInputCtrl->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } @@ -786,7 +785,7 @@ namespace MWInput ICS::Control* c = mInputCtrl->getChannel (action)->getAttachedControls ().front().control; - if (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE) != OIS::KC_UNASSIGNED) + if (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE) != SDLK_UNKNOWN) return mInputCtrl->keyCodeToString (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE)); else if (mInputCtrl->getMouseButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) return "#{sMouse} " + boost::lexical_cast(mInputCtrl->getMouseButtonBinding (c, ICS::Control::INCREASE)); @@ -842,7 +841,7 @@ namespace MWInput } void InputManager::keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , OIS::KeyCode key, ICS::Control::ControlChangingDirection direction) + , SDL_Keycode key, ICS::Control::ControlChangingDirection direction) { clearAllBindings(control); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); @@ -892,7 +891,7 @@ namespace MWInput void InputManager::clearAllBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first - if (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) != OIS::KC_UNASSIGNED) + if (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) != SDLK_UNKNOWN) mInputCtrl->removeKeyBinding (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE)); if (mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) mInputCtrl->removeMouseButtonBinding (mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE)); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f28..3677f9070 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -6,6 +6,7 @@ #include #include "../mwbase/inputmanager.hpp" +#include "sdlinputwrapper.hpp" namespace OEngine { @@ -35,18 +36,9 @@ namespace ICS class InputControlSystem; } -namespace OIS -{ - class Keyboard; - class Mouse; - class InputManager; -} - -#include -#include - #include #include +#include namespace MWInput { @@ -54,7 +46,12 @@ namespace MWInput /** * @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 ICS::DetectingBindingListener + class InputManager : + public MWBase::InputManager, + public ICS::MWSDLKeyListener, + public ICS::MWSDLMouseListener, + public ICS::ChannelListener, + public ICS::DetectingBindingListener { public: InputManager(OEngine::Render::OgreRenderer &_ogre, @@ -85,12 +82,12 @@ namespace MWInput virtual void resetToDefaultBindings(); public: - virtual bool keyPressed( const OIS::KeyEvent &arg ); - virtual bool keyReleased( const OIS::KeyEvent &arg ); + virtual bool keyPressed(const SDL_KeyboardEvent &arg ); + virtual bool keyReleased( const SDL_KeyboardEvent &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 bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ); + virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); + virtual bool mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ); virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue); @@ -98,7 +95,7 @@ namespace MWInput , ICS::InputControlSystem::NamedAxis axis, ICS::Control::ControlChangingDirection direction); virtual void keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , OIS::KeyCode key, ICS::Control::ControlChangingDirection direction); + , SDL_Keycode key, ICS::Control::ControlChangingDirection direction); virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction); @@ -125,9 +122,8 @@ namespace MWInput ICS::InputControlSystem* mInputCtrl; - OIS::Keyboard* mKeyboard; - OIS::Mouse* mMouse; - OIS::InputManager* mInputManager; + + MWSDLInputWrapper* mInputManager; std::string mUserFile; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp new file mode 100644 index 000000000..60c7e8f7a --- /dev/null +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -0,0 +1,70 @@ +#include "sdlinputwrapper.hpp" +#include + +namespace MWInput +{ + MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) : + mWindow(window), mStarted(false), mSDLWindow(NULL) + { + _start(); + } + + MWSDLInputWrapper::~MWSDLInputWrapper() + { + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + SDL_Quit(); + } + + void MWSDLInputWrapper::capture() + { + _start(); + + SDL_Event evt; + while(SDL_PollEvent(&evt)) + { + switch(evt.type) + { + case SDL_MOUSEMOTION: + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); + break; + case SDL_MOUSEWHEEL: + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); + break; + case SDL_MOUSEBUTTONDOWN: + mMouseListener->mousePressed(evt.button, evt.button.button); + break; + case SDL_MOUSEBUTTONUP: + mMouseListener->mouseReleased(evt.button, evt.button.button); + break; + + case SDL_KEYDOWN: + mKeyboardListener->keyPressed(evt.key); + break; + case SDL_KEYUP: + mKeyboardListener->keyReleased(evt.key); + break; + } + } + } + + bool MWSDLInputWrapper::isModifierHeld(int mod) + { + return SDL_GetModState() & mod; + } + + void MWSDLInputWrapper::_start() + { + Uint32 flags = SDL_INIT_VIDEO; + if(SDL_WasInit(flags) == 0) + { + //get the HWND from ogre's renderwindow + size_t windowHnd; + mWindow->getCustomAttribute("WINDOW", &windowHnd); + + //just use that one for input + SDL_Init(flags); + mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + } + } +} diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp new file mode 100644 index 000000000..ee07efbdb --- /dev/null +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -0,0 +1,35 @@ +#ifndef _MWINPUT_SDLINPUTWRAPPER_H +#define _MWINPUT_SDLINPUTWRAPPER_H + +#include "SDL2/SDL_events.h" +#include +#include + + +namespace MWInput +{ + class MWSDLInputWrapper + { + public: + MWSDLInputWrapper(Ogre::RenderWindow* window); + ~MWSDLInputWrapper(); + + void setMouseEventCallback(ICS::MWSDLMouseListener* listen) { mMouseListener = listen; } + void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; } + + void capture(); + bool isModifierHeld(int mod); + + private: + ICS::MWSDLMouseListener* mMouseListener; + ICS::MWSDLKeyListener* mKeyboardListener; + Ogre::RenderWindow* mWindow; + SDL_Window* mSDLWindow; + + bool mStarted; + void _start(); + + }; +} + +#endif diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake new file mode 100644 index 000000000..614426ccc --- /dev/null +++ b/cmake/FindSDL2.cmake @@ -0,0 +1,180 @@ +# Locate SDL2 library +# This module defines +# SDL2_LIBRARY, the name of the library to link against +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2_main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARY variable. +# +# Don't forget to include SDL2main.h and SDL2main.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library +# (SDL2.dll, libsdl2.so, SDL2.framework, etc). +# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL2_LIBRARY +# variable, but when these values are unset, SDL2_LIBRARY does not get created. +# +# +# $SDL2DIR is an environment variable that would +# correspond to the ./configure --prefix=$SDL2DIR +# used in building SDL2. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL2 guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL2 convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). +# +# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake +# module with the minor edit of changing "SDL" to "SDL2" where necessary. This +# was not created for redistribution, and exists temporarily pending official +# SDL2 CMake modules. + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +FIND_PATH(SDL2_INCLUDE_DIR SDL.h + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES include/SDL2 include + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include/SDL2 + /usr/include/SDL2 + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) +#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}") + +FIND_LIBRARY(SDL2_LIBRARY_TEMP + NAMES SDL2 + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS + /sw + /opt/local + /opt/csw + /opt +) + +#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}") + +IF(NOT SDL2_BUILDING_LIBRARY) + IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + FIND_LIBRARY(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) + ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") +ENDIF(NOT SDL2_BUILDING_LIBRARY) + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +SET(SDL2_FOUND "NO") +IF(SDL2_LIBRARY_TEMP) + # For SDL2main + IF(NOT SDL2_BUILDING_LIBRARY) + IF(SDL2MAIN_LIBRARY) + SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(SDL2MAIN_LIBRARY) + ENDIF(NOT SDL2_BUILDING_LIBRARY) + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + IF(APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") + ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + IF(NOT APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(NOT APPLE) + + # For MinGW library + IF(MINGW) + SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") + + SET(SDL2_FOUND "YES") +ENDIF(SDL2_LIBRARY_TEMP) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 + REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) diff --git a/extern/oics/CMakeLists.txt b/extern/oics/CMakeLists.txt index 7c14387a4..2e2a7a6d6 100644 --- a/extern/oics/CMakeLists.txt +++ b/extern/oics/CMakeLists.txt @@ -9,6 +9,7 @@ set(OICS_SOURCE_FILES ICSInputControlSystem_keyboard.cpp ICSInputControlSystem_mouse.cpp ICSInputControlSystem_joystick.cpp + OISCompat.h tinyxml.cpp tinyxmlparser.cpp tinyxmlerror.cpp diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 1702c853e..159b3241f 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -41,7 +41,7 @@ namespace ICS this->mActive = active; - this->fillOISKeysMap(); + this->fillSDLKeysMap(); ICS_LOG("Channel count = " + ToString(channelCount) ); for(size_t i=0;i::iterator it = mKeys.begin() + for(std::map::iterator it = mKeys.begin() ; it != mKeys.end() ; it++) { mKeyCodes[ it->second ] = it->first; } } - std::string InputControlSystem::keyCodeToString(OIS::KeyCode key) + std::string InputControlSystem::keyCodeToString(SDL_Keycode key) { return mKeyCodes[key]; } - OIS::KeyCode InputControlSystem::stringToKeyCode(std::string key) + SDL_Keycode InputControlSystem::stringToKeyCode(std::string key) { return mKeys[key]; } -} \ No newline at end of file + + void InputControlSystem::adjustMouseRegion(Uint16 width, Uint16 height) + { + mClientWidth = width; + mClientHeight = height; + } +} diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index f1c12d3b5..5d30b35cf 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,6 +32,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" +#include "OISCompat.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 @@ -48,9 +50,9 @@ namespace ICS }; class DllExport InputControlSystem : - public OIS::MouseListener, - public OIS::KeyListener, - public OIS::JoyStickListener + public MWSDLMouseListener, + public MWSDLKeyListener, + public MWSDLJoyStickListener { public: @@ -100,29 +102,30 @@ namespace ICS 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); + bool mouseMoved(const MWSDLMouseMotionEvent &evt); + bool mousePressed(const SDL_MouseButtonEvent &evt, Uint8); + bool mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); // KeyListener - bool keyPressed(const OIS::KeyEvent &evt); - bool keyReleased(const OIS::KeyEvent &evt); + bool keyPressed(const SDL_KeyboardEvent &evt); + bool keyReleased(const SDL_KeyboardEvent &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); + bool buttonPressed(const SDL_JoyButtonEvent &evt, int button); + bool buttonReleased(const SDL_JoyButtonEvent &evt, int button); + bool axisMoved(const SDL_JoyAxisEvent &evt, int axis); + bool povMoved(const SDL_JoyHatEvent &evt, int index); + //TODO: does this have an SDL equivalent? + //bool sliderMoved(const OIS::JoyStickEvent &evt, int index); - void addKeyBinding(Control* control, OIS::KeyCode key, Control::ControlChangingDirection direction); + void addKeyBinding(Control* control, SDL_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 removeKeyBinding(SDL_Keycode key); void removeMouseAxisBinding(NamedAxis axis); void removeMouseButtonBinding(unsigned int button); void removeJoystickAxisBinding(int deviceId, int axis); @@ -130,7 +133,7 @@ namespace ICS void removeJoystickPOVBinding(int deviceId, int index, POVAxis axis); void removeJoystickSliderBinding(int deviceId, int index); - OIS::KeyCode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); + SDL_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); @@ -138,14 +141,16 @@ namespace ICS 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); + std::string keyCodeToString(SDL_Keycode key); + SDL_Keycode stringToKeyCode(std::string key); void enableDetectingBindingState(Control* control, Control::ControlChangingDirection direction); void cancelDetectingBindingState(); bool save(std::string fileName = ""); + void adjustMouseRegion (Uint16 width, Uint16 height); + protected: void loadKeyBinders(TiXmlElement* xmlControlNode); @@ -180,7 +185,7 @@ namespace ICS std::string mFileName; - typedef std::map ControlsKeyBinderMapType; // + typedef std::map ControlsKeyBinderMapType; // typedef std::map ControlsAxisBinderMapType; // typedef std::map ControlsButtonBinderMapType; // typedef std::map ControlsPOVBinderMapType; // @@ -202,8 +207,8 @@ namespace ICS std::vector mChannels; ControlsKeyBinderMapType mControlsKeyBinderMap; - std::map mKeys; - std::map mKeyCodes; + std::map mKeys; + std::map mKeyCodes; bool mActive; InputControlSystemLog* mLog; @@ -221,14 +226,17 @@ namespace ICS private: - void fillOISKeysMap(); + void fillSDLKeysMap(); + + Uint16 mClientWidth; + Uint16 mClientHeight; }; class DllExport DetectingBindingListener { public: virtual void keyBindingDetected(InputControlSystem* ICS, Control* control - , OIS::KeyCode key, Control::ControlChangingDirection direction); + , SDL_Keycode key, Control::ControlChangingDirection direction); virtual void mouseAxisBindingDetected(InputControlSystem* ICS, Control* control , InputControlSystem::NamedAxis axis, Control::ControlChangingDirection direction); diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index 1e66599ea..8e501d501 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -26,6 +26,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSInputControlSystem.h" +#define SDL_JOY_AXIS_MIN -32768 +#define SDL_JOY_AXIS_MAX 32767 + namespace ICS { // load xml @@ -315,16 +318,16 @@ namespace ICS } // joyStick listeners - bool InputControlSystem::buttonPressed(const OIS::JoyStickEvent &evt, int button) + bool InputControlSystem::buttonPressed(const SDL_JoyButtonEvent &evt, int button) { if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickButtonBinderMap.find(evt.device->getID()) != mControlsJoystickButtonBinderMap.end()) + if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.device->getID()].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.device->getID()].end()) + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); + if(it != mControlsJoystickButtonBinderMap[evt.which].end()) { it->second.control->setIgnoreAutoReverse(false); if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) @@ -348,21 +351,21 @@ namespace ICS else if(mDetectingBindingListener) { mDetectingBindingListener->joystickButtonBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), button, mDetectingBindingDirection); + mDetectingBindingControl, evt.which, button, mDetectingBindingDirection); } } return true; } - bool InputControlSystem::buttonReleased(const OIS::JoyStickEvent &evt, int button) + bool InputControlSystem::buttonReleased(const SDL_JoyButtonEvent &evt, int button) { if(mActive) { - if(mControlsJoystickButtonBinderMap.find(evt.device->getID()) != mControlsJoystickButtonBinderMap.end()) + if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.device->getID()].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.device->getID()].end()) + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); + if(it != mControlsJoystickButtonBinderMap[evt.which].end()) { it->second.control->setChangingDirection(Control::STOP); } @@ -371,31 +374,29 @@ namespace ICS return true; } - bool InputControlSystem::axisMoved(const OIS::JoyStickEvent &evt, int axis) - { + bool InputControlSystem::axisMoved(const SDL_JoyAxisEvent &evt, int axis) + { if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickAxisBinderMap.find(evt.device->getID()) != mControlsJoystickAxisBinderMap.end()) + if(mControlsJoystickAxisBinderMap.find(evt.which) != mControlsJoystickAxisBinderMap.end()) { - ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.device->getID() ][ axis ]; // joystic axis start at 0 index + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ axis ]; // joystic axis start at 0 index Control* ctrl = joystickBinderItem.control; if(ctrl) { ctrl->setIgnoreAutoReverse(true); + + float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MAX; + float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + 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 ) ); } } @@ -403,15 +404,15 @@ namespace ICS } else if(mDetectingBindingListener) { - //ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.device->getID() ][ axis ]; // joystic axis start at 0 index + //ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ 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) + if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) { mDetectingBindingListener->joystickAxisBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), axis, mDetectingBindingDirection); + mDetectingBindingControl, evt.which, axis, mDetectingBindingDirection); } } } @@ -420,20 +421,21 @@ namespace ICS return true; } - bool InputControlSystem::povMoved(const OIS::JoyStickEvent &evt, int index) - { + //Here be dragons, apparently + bool InputControlSystem::povMoved(const SDL_JoyHatEvent &evt, int index) + { if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickPOVBinderMap.find(evt.device->getID()) != mControlsJoystickPOVBinderMap.end()) + if(mControlsJoystickPOVBinderMap.find(evt.which) != mControlsJoystickPOVBinderMap.end()) { - std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.device->getID() ].find(index); - if(i != mControlsJoystickPOVBinderMap[ evt.device->getID() ].end()) + std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.which ].find(index); + if(i != mControlsJoystickPOVBinderMap[ evt.which ].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) + if(evt.value != SDL_HAT_LEFT + && evt.value != SDL_HAT_RIGHT + && evt.value != SDL_HAT_CENTERED) { ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); if(it != i->second.end()) @@ -441,9 +443,9 @@ namespace ICS 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) + if(evt.value == SDL_HAT_UP + || evt.value == SDL_HAT_LEFTUP + || evt.value == SDL_HAT_RIGHTUP) { it->second.control->setChangingDirection(it->second.direction); } @@ -453,7 +455,7 @@ namespace ICS } } else - { + { if(it->second.control->getValue() == 1) { it->second.control->setChangingDirection(Control::DECREASE); @@ -466,9 +468,9 @@ namespace ICS } } - 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) + if(evt.value != SDL_HAT_UP + && evt.value != SDL_HAT_DOWN + && evt.value != SDL_HAT_CENTERED) { ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/EastWest ); if(it != i->second.end()) @@ -476,9 +478,9 @@ namespace ICS 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) + if(evt.value == SDL_HAT_RIGHT + || evt.value == SDL_HAT_RIGHTUP + || evt.value == SDL_HAT_RIGHTDOWN) { it->second.control->setChangingDirection(it->second.direction); } @@ -488,7 +490,7 @@ namespace ICS } } else - { + { if(it->second.control->getValue() == 1) { it->second.control->setChangingDirection(Control::DECREASE); @@ -501,7 +503,7 @@ namespace ICS } } - if(evt.state.mPOV[index].direction == OIS::Pov::Centered) + if(evt.value == SDL_HAT_CENTERED) { ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); if(it != i->second.end()) @@ -522,28 +524,30 @@ namespace ICS { 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) + if(evt.value == SDL_HAT_LEFT + || evt.value == SDL_HAT_RIGHT + || evt.value == SDL_HAT_UP + || evt.value == SDL_HAT_DOWN) { POVAxis povAxis = NorthSouth; - if(evt.state.mPOV[index].direction == OIS::Pov::West - || evt.state.mPOV[index].direction == OIS::Pov::East) + if(evt.value == SDL_HAT_LEFT + || evt.value == SDL_HAT_RIGHT) { povAxis = EastWest; } mDetectingBindingListener->joystickPOVBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), index, povAxis, mDetectingBindingDirection); + mDetectingBindingControl, evt.which, index, povAxis, mDetectingBindingDirection); } } } } - + return true; } + //TODO: does this have an SDL equivalent? + /* bool InputControlSystem::sliderMoved(const OIS::JoyStickEvent &evt, int index) { if(mActive) @@ -552,7 +556,7 @@ namespace ICS { if(mControlsJoystickSliderBinderMap.find(evt.device->getID()) != mControlsJoystickSliderBinderMap.end()) { - ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; + ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; Control* ctrl = joystickBinderItem.control; if(ctrl) { @@ -576,10 +580,6 @@ namespace ICS } 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) @@ -593,6 +593,7 @@ namespace ICS return true; } + */ // joystick auto bindings void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control @@ -662,4 +663,4 @@ namespace ICS 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 index 8ef81d979..01d68f784 100644 --- a/extern/oics/ICSInputControlSystem_keyboard.cpp +++ b/extern/oics/ICSInputControlSystem_keyboard.cpp @@ -49,7 +49,7 @@ namespace ICS } } - void InputControlSystem::addKeyBinding(Control* control, OIS::KeyCode key, Control::ControlChangingDirection direction) + void InputControlSystem::addKeyBinding(Control* control, SDL_Keycode key, Control::ControlChangingDirection direction) { ICS_LOG("\tAdding KeyBinder [key=" + keyCodeToString(key) + ", direction=" @@ -61,7 +61,7 @@ namespace ICS mControlsKeyBinderMap[ key ] = controlKeyBinderItem; } - void InputControlSystem::removeKeyBinding(OIS::KeyCode key) + void InputControlSystem::removeKeyBinding(SDL_Keycode key) { ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.find(key); if(it != mControlsKeyBinderMap.end()) @@ -70,7 +70,7 @@ namespace ICS } } - OIS::KeyCode InputControlSystem::getKeyBinding(Control* control + SDL_Keycode InputControlSystem::getKeyBinding(Control* control , ICS::Control::ControlChangingDirection direction) { ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.begin(); @@ -83,15 +83,15 @@ namespace ICS it++; } - return OIS::KC_UNASSIGNED; + return SDLK_UNKNOWN; } - bool InputControlSystem::keyPressed(const OIS::KeyEvent &evt) + bool InputControlSystem::keyPressed(const SDL_KeyboardEvent &evt) { if(mActive) { if(!mDetectingBindingControl) { - ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.key); + ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.keysym.sym); if(it != mControlsKeyBinderMap.end()) { it->second.control->setIgnoreAutoReverse(false); @@ -115,18 +115,18 @@ namespace ICS else if(mDetectingBindingListener) { mDetectingBindingListener->keyBindingDetected(this, - mDetectingBindingControl, evt.key, mDetectingBindingDirection); + mDetectingBindingControl, evt.keysym.sym, mDetectingBindingDirection); } } return true; } - bool InputControlSystem::keyReleased(const OIS::KeyEvent &evt) + bool InputControlSystem::keyReleased(const SDL_KeyboardEvent &evt) { if(mActive) { - ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.key); + ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.keysym.sym); if(it != mControlsKeyBinderMap.end()) { it->second.control->setChangingDirection(Control::STOP); @@ -137,14 +137,14 @@ namespace ICS } void DetectingBindingListener::keyBindingDetected(InputControlSystem* ICS, Control* control - , OIS::KeyCode key, Control::ControlChangingDirection direction) + , SDL_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) + SDL_Keycode oldKey = ICS->getKeyBinding(control, direction); + if(oldKey != SDLK_UNKNOWN) { ICS->removeKeyBinding(oldKey); } @@ -153,4 +153,4 @@ namespace ICS ICS->cancelDetectingBindingState(); } -} \ No newline at end of file +} diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index c62f1765e..96197426a 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -78,15 +78,15 @@ namespace ICS int button = 0; if(std::string(xmlMouseButtonBinder->Attribute("button")) == "LEFT") { - button = OIS::/*MouseButtonID::*/MB_Left; + button = SDL_BUTTON_LEFT; } else if(std::string(xmlMouseButtonBinder->Attribute("button")) == "RIGHT") { - button = OIS::/*MouseButtonID::*/MB_Right; + button = SDL_BUTTON_RIGHT; } else if(std::string(xmlMouseButtonBinder->Attribute("button")) == "MIDDLE") { - button = OIS::/*MouseButtonID::*/MB_Middle; + button = SDL_BUTTON_MIDDLE; } else { @@ -219,39 +219,39 @@ namespace ICS } // mouse Listeners - bool InputControlSystem::mouseMoved(const OIS::MouseEvent &evt) + bool InputControlSystem::mouseMoved(const MWSDLMouseMotionEvent& evt) { if(mActive) { if(!mDetectingBindingControl) { - if(mXmouseAxisBinded && evt.state.X.rel) + if(mXmouseAxisBinded && evt.xrel) { 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) ) ); + ctrl->setValue( float( (evt.x) / float(mClientWidth) ) ); } else if(mouseBinderItem.direction == Control::DECREASE) { - ctrl->setValue( 1 - float( evt.state.X.abs / float(evt.state.width) ) ); + ctrl->setValue( 1 - float( evt.x / float(mClientWidth) ) ); } } - if(mYmouseAxisBinded && evt.state.Y.rel) + if(mYmouseAxisBinded && evt.yrel) { 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) ) ); + ctrl->setValue( float( (evt.y) / float(mClientHeight) ) ); } else if(mouseBinderItem.direction == Control::DECREASE) { - ctrl->setValue( 1 - float( evt.state.Y.abs / float(evt.state.height) ) ); + ctrl->setValue( 1 - float( evt.y / float(mClientHeight) ) ); } } @@ -282,9 +282,9 @@ namespace ICS mMouseAxisBindingInitialValues[2] = 0; } - mMouseAxisBindingInitialValues[0] += evt.state.X.rel; - mMouseAxisBindingInitialValues[1] += evt.state.Y.rel; - mMouseAxisBindingInitialValues[2] += evt.state.Z.rel; + mMouseAxisBindingInitialValues[0] += evt.xrel; + mMouseAxisBindingInitialValues[1] += evt.yrel; + mMouseAxisBindingInitialValues[2] += evt.zrel; if( abs(mMouseAxisBindingInitialValues[0]) > ICS_MOUSE_BINDING_MARGIN ) { @@ -308,7 +308,7 @@ namespace ICS return true; } - bool InputControlSystem::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) + bool InputControlSystem::mousePressed(const SDL_MouseButtonEvent &evt, Uint8 btn) { if(mActive) { @@ -345,7 +345,7 @@ namespace ICS return true; } - bool InputControlSystem::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) + bool InputControlSystem::mouseReleased(const SDL_MouseButtonEvent &evt, Uint8 btn) { if(mActive) { @@ -394,4 +394,4 @@ namespace ICS ICS->cancelDetectingBindingState(); } -} \ No newline at end of file +} diff --git a/extern/oics/ICSPrerequisites.h b/extern/oics/ICSPrerequisites.h index 3b5d1935b..82c95c86a 100644 --- a/extern/oics/ICSPrerequisites.h +++ b/extern/oics/ICSPrerequisites.h @@ -39,11 +39,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tinyxml.h" -#include -#include -#include -#include -#include +#include "SDL2/SDL_input.h" +#include "SDL2/SDL_keyboard.h" +#include "SDL2/SDL_mouse.h" +#include "SDL2/SDL_joystick.h" +#include "SDL2/SDL_events.h" /// Define the dll export qualifier if compiling for Windows @@ -65,8 +65,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /// Version defines #define ICS_VERSION_MAJOR 0 -#define ICS_VERSION_MINOR 3 -#define ICS_VERSION_PATCH 1 +#define ICS_VERSION_MINOR 4 +#define ICS_VERSION_PATCH 0 #define ICS_MAX_DEVICE_BUTTONS 30 diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h new file mode 100644 index 000000000..18bdd6bae --- /dev/null +++ b/extern/oics/OISCompat.h @@ -0,0 +1,90 @@ +#ifndef _OIS_SDL_COMPAT_H +#define _OIS_SDL_COMPAT_H + +#include +#include + +//TODO: Remove this. Right now we want to remain as close to OIS as possible +//So we can easily test the SDL backend + +//////////// +// Events // +//////////// + +namespace ICS { + +/** Extended mouse event struct where we treat the wheel like an axis, like everyone expects */ +struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { + + Sint16 zrel; + + MWSDLMouseMotionEvent() + { + x = 0; + y = 0; + xrel = 0; + yrel = 0; + state = 0; + zrel = 0; + } + + MWSDLMouseMotionEvent( const SDL_MouseMotionEvent& evt) : + MWSDLMouseMotionEvent() + { + x = evt.x; + y = evt.y; + xrel = evt.xrel; + yrel = evt.yrel; + state = evt.state; + } + + MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) : + MWSDLMouseMotionEvent() + { + zrel = evt.y; + } +}; + + +/////////////// +// Listeners // +/////////////// + +class MWSDLMouseListener +{ +public: + virtual ~MWSDLMouseListener() {} + virtual bool mouseMoved( const MWSDLMouseMotionEvent &arg ) = 0; + virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) = 0; + virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) = 0; +}; + +class MWSDLKeyListener +{ +public: + virtual ~MWSDLKeyListener() {} + virtual bool keyPressed(const SDL_KeyboardEvent &arg) = 0; + virtual bool keyReleased(const SDL_KeyboardEvent &arg) = 0; +}; + +class MWSDLJoyStickListener +{ +public: + virtual ~MWSDLJoyStickListener() {} + /** @remarks Joystick button down event */ + virtual bool buttonPressed( const SDL_JoyButtonEvent &evt, int button ) = 0; + + /** @remarks Joystick button up event */ + virtual bool buttonReleased( const SDL_JoyButtonEvent &evt, int button ) = 0; + + /** @remarks Joystick axis moved event */ + virtual bool axisMoved( const SDL_JoyAxisEvent &arg, int axis ) = 0; + + //-- Not so common control events, so are not required --// + + //! Joystick Event, and povID + virtual bool povMoved( const SDL_JoyHatEvent &arg, int index) {return true;} +}; + +} +#endif From 3b1d285cf3898dfaee3336836e81403f379fde75 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Tue, 8 Jan 2013 21:01:58 -0400 Subject: [PATCH 002/817] fix compile errors, work with unmodified SDL --- apps/openmw/mwinput/sdlinputwrapper.cpp | 50 ++++++++++++++++++++++++- extern/oics/OISCompat.h | 22 +++++++---- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index 60c7e8f7a..61fc3fc8b 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -1,5 +1,15 @@ #include "sdlinputwrapper.hpp" #include +#include + +#include + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +# include +# include +# include +#endif + namespace MWInput { @@ -62,9 +72,45 @@ namespace MWInput size_t windowHnd; mWindow->getCustomAttribute("WINDOW", &windowHnd); - //just use that one for input - SDL_Init(flags); + //kindly ask SDL not to trash our OGL context + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + SDL_Init(SDL_INIT_VIDEO); + + //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX + //linux-specific event-handling fixups + SDL_SysWMinfo wm_info; + SDL_VERSION(&wm_info.version); + + if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) + { + printf("SDL version %d.%d.%d\n", wm_info.version.major, wm_info.version.minor, wm_info.version.patch); + + Display* display = wm_info.info.x11.display; + Window w = wm_info.info.x11.window; + + // Set the input hints so we get keyboard input + XWMHints *wmhints = XAllocWMHints(); + if (wmhints) { + wmhints->input = True; + wmhints->flags = InputHint; + XSetWMHints(display, w, wmhints); + XFree(wmhints); + } + + //make sure to subscribe to XLib's events + XSelectInput(display, w, + (FocusChangeMask | EnterWindowMask | LeaveWindowMask | + ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | KeyPressMask | KeyReleaseMask | + PropertyChangeMask | StructureNotifyMask | + KeymapStateMask)); + + XFlush(display); + } +#endif } } } diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h index 18bdd6bae..74b6acde1 100644 --- a/extern/oics/OISCompat.h +++ b/extern/oics/OISCompat.h @@ -20,17 +20,12 @@ struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { MWSDLMouseMotionEvent() { - x = 0; - y = 0; - xrel = 0; - yrel = 0; - state = 0; - zrel = 0; + _init(); } - MWSDLMouseMotionEvent( const SDL_MouseMotionEvent& evt) : - MWSDLMouseMotionEvent() + MWSDLMouseMotionEvent( const SDL_MouseMotionEvent& evt) { + _init(); x = evt.x; y = evt.y; xrel = evt.xrel; @@ -41,8 +36,19 @@ struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) : MWSDLMouseMotionEvent() { + _init(); zrel = evt.y; } + + void _init() + { + x = 0; + y = 0; + xrel = 0; + yrel = 0; + state = 0; + zrel = 0; + } }; From 00a2a5c358e8a4ee189f92f7b0423605b3a308a2 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Tue, 8 Jan 2013 21:04:36 -0400 Subject: [PATCH 003/817] remove some more of my mess --- extern/oics/OISCompat.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h index 74b6acde1..e8fd6904c 100644 --- a/extern/oics/OISCompat.h +++ b/extern/oics/OISCompat.h @@ -33,8 +33,7 @@ struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { state = evt.state; } - MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) : - MWSDLMouseMotionEvent() + MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) { _init(); zrel = evt.y; From 6b49b8ab47e4dcbd363a3ae281b55026c2b5759a Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Tue, 8 Jan 2013 22:14:30 -0400 Subject: [PATCH 004/817] MyGUI doesn't care for SDL's mouse button ordering, send it what it expects --- apps/openmw/mwinput/inputmanagerimp.cpp | 16 ++++++++++++++-- apps/openmw/mwinput/inputmanagerimp.hpp | 6 ++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9524381fb..f13eb9daf 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -450,7 +450,7 @@ namespace MWInput { mInputCtrl->mousePressed (arg, id); - MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id)); + MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { @@ -468,7 +468,7 @@ namespace MWInput { mInputCtrl->mouseReleased (arg, id); - MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id)); + MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); return true; } @@ -905,4 +905,16 @@ namespace MWInput { loadKeyDefaults(true); } + + MyGUI::MouseButton InputManager::sdlButtonToMyGUI(Uint8 button) + { + //The right button is the second button, according to MyGUI + if(button == SDL_BUTTON_RIGHT) + button = SDL_BUTTON_MIDDLE; + else if(button == SDL_BUTTON_MIDDLE) + button = SDL_BUTTON_RIGHT; + + //MyGUI's buttons are 0 indexed + return MyGUI::MouseButton::Enum(button - 1); + } } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 3677f9070..df6ce3c43 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -36,6 +36,11 @@ namespace ICS class InputControlSystem; } +namespace MyGUI +{ + class MouseButton; +} + #include #include #include @@ -149,6 +154,7 @@ namespace MWInput private: void adjustMouseRegion(int width, int height); + MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); void resetIdleTime(); void updateIdleTime(float dt); From 1bf36c686c5fd2c85eff2be5e08933a48df79c20 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 06:09:47 -0400 Subject: [PATCH 005/817] add ability to check if a window is on the stack (to see if we're in the main menu) --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 3 files changed, 10 insertions(+) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 30bfced06..13a35b592 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -88,6 +88,7 @@ namespace MWBase ///< can be anywhere in the stack virtual MWGui::GuiMode getMode() const = 0; + virtual bool containsMode(MWGui::GuiMode) const = 0; virtual bool isGuiMode() const = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8ec495550..d653b578a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -965,6 +965,14 @@ MWGui::GuiMode WindowManager::getMode() const return mGuiModes.back(); } +bool WindowManager::containsMode(GuiMode mode) const +{ + if(mGuiModes.empty()) + return false; + + return std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end(); +} + std::map > WindowManager::getPlayerSkillValues() { return mPlayerSkillValues; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8bcb88e22..e2a966660 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -97,6 +97,7 @@ namespace MWGui virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack virtual GuiMode getMode() const; + virtual bool containsMode(GuiMode mode) const; virtual bool isGuiMode() const; From 02ccb758949b64abe026766e141a562d53313feb Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 06:10:05 -0400 Subject: [PATCH 006/817] Wrap the mouse to the window (except in debug mode) Grab the mouse when not in the main menu (except in debug mode) Always hide the cursor when it's over the window Allow warping the mouse around Handle ^C properly --- apps/openmw/mwinput/inputmanagerimp.cpp | 75 +++++------ apps/openmw/mwinput/inputmanagerimp.hpp | 5 + apps/openmw/mwinput/sdlinputwrapper.cpp | 170 ++++++++++++++++++------ apps/openmw/mwinput/sdlinputwrapper.hpp | 22 ++- extern/oics/OISCompat.h | 12 ++ 5 files changed, 194 insertions(+), 90 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f13eb9daf..805f4926c 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -44,6 +44,7 @@ namespace MWInput , mUserFile(userFile) , mDragDrop(false) , mGuiCursorEnabled(false) + , mDebug(debug) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) @@ -52,50 +53,6 @@ namespace MWInput , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) { - Ogre::RenderWindow* window = ogre.getWindow (); - size_t windowHnd; - - resetIdleTime(); - - window->getCustomAttribute("WINDOW", &windowHnd); - - - // Set non-exclusive mouse and keyboard input if the user requested - // it. - - //TODO: re-enable this and make it work with SDL - /* - - std::ostringstream windowHndStr; - OIS::ParamList pl; - - windowHndStr << windowHnd; - pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); - - if (debug) - { - #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 - } - */ - #if defined(__APPLE__) && !defined(__LP64__) // Give the application window focus to receive input events ProcessSerialNumber psn = { 0, kCurrentProcess }; @@ -103,9 +60,12 @@ namespace MWInput SetFrontProcess(&psn); #endif + Ogre::RenderWindow* window = ogre.getWindow (); + mInputManager = new MWSDLInputWrapper(window); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); + mInputManager->setWindowEventCallback(this); std::string file = userFileExists ? userFile : ""; mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -256,6 +216,15 @@ namespace MWInput // event callbacks (which may crash) mWindows.update(); + if(!mDebug) + { + //don't keep the pointer away from the window edge in GUI mode + mInputManager->setWrapPointer(!mWindows.isGuiMode()); + + //we let the mouse escape in the main menu + mInputManager->setGrabPointer(!mWindows.containsMode(MWGui::GM_MainMenu)); + } + // Disable movement in Gui mode if (mWindows.isGuiMode()) return; @@ -510,6 +479,24 @@ namespace MWInput return true; } + bool InputManager::windowFocusChange(bool have_focus) + { + if(!mDebug) + { + + } + return true; + } + + bool InputManager::windowVisibilityChange(bool visible) + { + if(!mDebug) + { + //TODO: Pause game? + } + return true; + } + void InputManager::toggleMainMenu() { if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index df6ce3c43..9a7656a67 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -55,6 +55,7 @@ namespace MWInput public MWBase::InputManager, public ICS::MWSDLKeyListener, public ICS::MWSDLMouseListener, + public ICS::MWSDLWindowListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { @@ -94,6 +95,9 @@ namespace MWInput virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual bool mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ); + virtual bool windowVisibilityChange( bool visible ); + virtual bool windowFocusChange( bool have_focus ); + virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue); virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control @@ -145,6 +149,7 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mDebug; float mMouseX; float mMouseY; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index 61fc3fc8b..c8922cf3a 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -3,6 +3,7 @@ #include #include +#include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX # include @@ -14,7 +15,11 @@ namespace MWInput { MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) : - mWindow(window), mStarted(false), mSDLWindow(NULL) + mWindow(window), + mSDLWindow(NULL), + mWarpCompensate(false), + mWrapPointer(false), + mGrabPointer(false) { _start(); } @@ -26,44 +31,7 @@ namespace MWInput SDL_Quit(); } - void MWSDLInputWrapper::capture() - { - _start(); - - SDL_Event evt; - while(SDL_PollEvent(&evt)) - { - switch(evt.type) - { - case SDL_MOUSEMOTION: - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); - break; - case SDL_MOUSEWHEEL: - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); - break; - case SDL_MOUSEBUTTONDOWN: - mMouseListener->mousePressed(evt.button, evt.button.button); - break; - case SDL_MOUSEBUTTONUP: - mMouseListener->mouseReleased(evt.button, evt.button.button); - break; - - case SDL_KEYDOWN: - mKeyboardListener->keyPressed(evt.key); - break; - case SDL_KEYUP: - mKeyboardListener->keyReleased(evt.key); - break; - } - } - } - - bool MWSDLInputWrapper::isModifierHeld(int mod) - { - return SDL_GetModState() & mod; - } - - void MWSDLInputWrapper::_start() + bool MWSDLInputWrapper::_start() { Uint32 flags = SDL_INIT_VIDEO; if(SDL_WasInit(flags) == 0) @@ -74,11 +42,15 @@ namespace MWInput //kindly ask SDL not to trash our OGL context SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - SDL_Init(SDL_INIT_VIDEO); + if(SDL_Init(SDL_INIT_VIDEO) != 0) + return false; //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + if(mSDLWindow == NULL) + return false; + #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX //linux-specific event-handling fixups SDL_SysWMinfo wm_info; @@ -86,8 +58,6 @@ namespace MWInput if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) { - printf("SDL version %d.%d.%d\n", wm_info.version.major, wm_info.version.minor, wm_info.version.patch); - Display* display = wm_info.info.x11.display; Window w = wm_info.info.x11.window; @@ -111,6 +81,122 @@ namespace MWInput XFlush(display); } #endif + SDL_ShowCursor(SDL_FALSE); + } + + return true; + } + + void MWSDLInputWrapper::capture() + { + if(!_start()) + throw std::runtime_error(SDL_GetError()); + + SDL_Event evt; + while(SDL_PollEvent(&evt)) + { + switch(evt.type) + { + case SDL_MOUSEMOTION: + //ignore this if it happened due to a warp + if(!_handleWarpMotion(evt.motion)) + { + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); + + //try to keep the mouse inside the window + _wrapMousePointer(evt.motion); + } + break; + case SDL_MOUSEWHEEL: + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); + break; + case SDL_MOUSEBUTTONDOWN: + mMouseListener->mousePressed(evt.button, evt.button.button); + break; + case SDL_MOUSEBUTTONUP: + mMouseListener->mouseReleased(evt.button, evt.button.button); + break; + + case SDL_KEYDOWN: + mKeyboardListener->keyPressed(evt.key); + break; + case SDL_KEYUP: + mKeyboardListener->keyReleased(evt.key); + break; + + case SDL_WINDOWEVENT_FOCUS_GAINED: + mWindowListener->windowFocusChange(true); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + mWindowListener->windowFocusChange(false); + break; + case SDL_WINDOWEVENT_EXPOSED: + mWindowListener->windowVisibilityChange(true); + break; + case SDL_WINDOWEVENT_HIDDEN: + mWindowListener->windowVisibilityChange(false); + break; + + //SDL traps ^C signals, pass it to OGRE. + case SDL_QUIT: + Ogre::Root::getSingleton().queueEndRendering(); + break; + } + } + } + + bool MWSDLInputWrapper::isModifierHeld(int mod) + { + return SDL_GetModState() & mod; + } + + void MWSDLInputWrapper::warpMouse(int x, int y) + { + SDL_WarpMouseInWindow(mSDLWindow, x, y); + mWarpCompensate = true; + mWarpX = x; + mWarpY = y; + } + + void MWSDLInputWrapper::setGrabPointer(bool grab) + { + SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; + + mGrabPointer = grab; + SDL_SetWindowGrab(mSDLWindow, sdlGrab); + } + + bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) + { + if(!mWarpCompensate) return false; + + //this was a warp event, signal the caller to eat it. + if(evt.x == mWarpX && evt.y == mWarpY) + { + mWarpCompensate = false; + return true; + } + + return false; + } + + void MWSDLInputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) + { + if(!mWrapPointer || !mGrabPointer) return; + + int width = 0; + int height = 0; + + SDL_GetWindowSize(mSDLWindow, &width, &height); + + const int FUDGE_FACTOR_X = width / 4; + const int FUDGE_FACTOR_Y = height / 4; + + //warp the mouse if it's about to go outside the window + if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width + || evt.y - FUDGE_FACTOR_Y < 0 || evt.y + FUDGE_FACTOR_Y > height) + { + warpMouse(width / 2, height / 2); } } } diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp index ee07efbdb..d507073b8 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -16,19 +16,33 @@ namespace MWInput void setMouseEventCallback(ICS::MWSDLMouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; } + void setWindowEventCallback(ICS::MWSDLWindowListener* listen) { mWindowListener = listen; } void capture(); bool isModifierHeld(int mod); + void setWrapPointer(bool wrap) { mWrapPointer = wrap; } + void setGrabPointer(bool grab); + + void warpMouse(int x, int y); private: + bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); + void _wrapMousePointer(const SDL_MouseMotionEvent &evt); + + bool _start(); + ICS::MWSDLMouseListener* mMouseListener; ICS::MWSDLKeyListener* mKeyboardListener; + ICS::MWSDLWindowListener* mWindowListener; + + Uint16 mWarpX; + Uint16 mWarpY; + bool mWarpCompensate; + bool mWrapPointer; + bool mGrabPointer; + Ogre::RenderWindow* mWindow; SDL_Window* mSDLWindow; - - bool mStarted; - void _start(); - }; } diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h index e8fd6904c..5813c17bf 100644 --- a/extern/oics/OISCompat.h +++ b/extern/oics/OISCompat.h @@ -91,5 +91,17 @@ public: virtual bool povMoved( const SDL_JoyHatEvent &arg, int index) {return true;} }; +class MWSDLWindowListener +{ +public: + virtual ~MWSDLWindowListener() {} + + /** @remarks The window's visibility changed */ + virtual bool windowVisibilityChange( bool visible ) = 0; + + /** @remarks The window got / lost input focus */ + virtual bool windowFocusChange( bool have_focus ) = 0; +}; + } #endif From 53cff0ba68f72d49834c9effbf1771a05a9d9a42 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 09:05:47 -0400 Subject: [PATCH 007/817] use native relative mouse movements where available, have the cursor follow the hardware cursor in the main menu --- apps/openmw/mwinput/inputmanagerimp.cpp | 40 ++++++++++++++++++++----- apps/openmw/mwinput/sdlinputwrapper.cpp | 37 ++++++++++++++++++++--- apps/openmw/mwinput/sdlinputwrapper.hpp | 4 ++- 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 805f4926c..17251aff5 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -218,11 +218,23 @@ namespace MWInput if(!mDebug) { - //don't keep the pointer away from the window edge in GUI mode - mInputManager->setWrapPointer(!mWindows.isGuiMode()); + bool main_menu = mWindows.containsMode(MWGui::GM_MainMenu); + + bool was_relative = mInputManager->getMouseRelative(); + bool is_relative = !main_menu; + + //don't keep the pointer away from the window edge in the main menu + mInputManager->setMouseRelative(is_relative); + + //we switched to non-relative mode, move our cursor to where the in-game + //cursor is + if( !is_relative && was_relative != is_relative ) + { + mInputManager->warpMouse(mMouseX, mMouseY); + } //we let the mouse escape in the main menu - mInputManager->setGrabPointer(!mWindows.containsMode(MWGui::GM_MainMenu)); + mInputManager->setGrabPointer(!main_menu); } // Disable movement in Gui mode @@ -454,8 +466,19 @@ namespace MWInput // 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 += float(arg.xrel) * mUISensitivity; - mMouseY += float(arg.yrel) * mUISensitivity * mUIYMultiplier; + + //FIXME: Except in the main menu, since we let the pointer escape + if(!mWindows.containsMode(MWGui::GM_MainMenu)) + { + mMouseX += float(arg.xrel) * mUISensitivity; + mMouseY += float(arg.yrel) * mUISensitivity * mUIYMultiplier; + } + else + { + mMouseX = arg.x; + mMouseY = arg.y; + } + mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); @@ -499,10 +522,11 @@ namespace MWInput void InputManager::toggleMainMenu() { - if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) - mWindows.popGuiMode(); - else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) + //TODO: should this be here? + if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) MWBase::Environment::get().getWorld ()->stopVideo (); + else if (mWindows.containsMode(MWGui::GM_MainMenu)) + mWindows.popGuiMode(); else mWindows.pushGuiMode (MWGui::GM_MainMenu); } diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index c8922cf3a..32f453b0f 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -18,8 +18,9 @@ namespace MWInput mWindow(window), mSDLWindow(NULL), mWarpCompensate(false), - mWrapPointer(false), - mGrabPointer(false) + mMouseRelative(false), + mGrabPointer(false), + mWrapPointer(false) { _start(); } @@ -166,9 +167,34 @@ namespace MWInput SDL_SetWindowGrab(mSDLWindow, sdlGrab); } + void MWSDLInputWrapper::setMouseRelative(bool relative) + { + if(mMouseRelative == relative) + return; + + mMouseRelative = relative; + + mWrapPointer = false; + + //eep, wrap the pointer manually if the input driver doesn't support + //relative positioning natively + if(SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == -1) + { + if(relative) + mWrapPointer = true; + } + + //now remove all mouse events using the old setting from the queue + SDL_PumpEvents(); + + SDL_Event dummy[20]; + SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); + } + bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) { - if(!mWarpCompensate) return false; + if(!mWarpCompensate) + return false; //this was a warp event, signal the caller to eat it. if(evt.x == mWarpX && evt.y == mWarpY) @@ -182,7 +208,10 @@ namespace MWInput void MWSDLInputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) { - if(!mWrapPointer || !mGrabPointer) return; + //don't wrap if we don't want relative movements, support relative + //movements natively, or aren't grabbing anyways + if(!mMouseRelative || !mWrapPointer || !mGrabPointer) + return; int width = 0; int height = 0; diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp index d507073b8..c2770ae7e 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -21,7 +21,8 @@ namespace MWInput void capture(); bool isModifierHeld(int mod); - void setWrapPointer(bool wrap) { mWrapPointer = wrap; } + void setMouseRelative(bool relative); + bool getMouseRelative() { return mMouseRelative; } void setGrabPointer(bool grab); void warpMouse(int x, int y); @@ -38,6 +39,7 @@ namespace MWInput Uint16 mWarpX; Uint16 mWarpY; bool mWarpCompensate; + bool mMouseRelative; bool mWrapPointer; bool mGrabPointer; From cb01df49c01f8e1391c62d3a1fd0a64b51bc81ff Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 11:30:33 -0400 Subject: [PATCH 008/817] begin to support text input --- apps/openmw/mwinput/inputmanagerimp.cpp | 1 + apps/openmw/mwinput/sdlinputwrapper.cpp | 27 +++++++++++++++++++++++-- apps/openmw/mwinput/sdlinputwrapper.hpp | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 17251aff5..763e75ae7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -413,6 +413,7 @@ namespace MWInput } #endif */ + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.keysym.sym), text); return true; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index 32f453b0f..56b3568f5 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -27,8 +27,10 @@ namespace MWInput MWSDLInputWrapper::~MWSDLInputWrapper() { - SDL_DestroyWindow(mSDLWindow); + if(mSDLWindow != NULL) + SDL_DestroyWindow(mSDLWindow); mSDLWindow = NULL; + SDL_StopTextInput(); SDL_Quit(); } @@ -52,6 +54,8 @@ namespace MWInput if(mSDLWindow == NULL) return false; + SDL_StartTextInput(); + #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX //linux-specific event-handling fixups SDL_SysWMinfo wm_info; @@ -119,7 +123,7 @@ namespace MWInput break; case SDL_KEYDOWN: - mKeyboardListener->keyPressed(evt.key); + _handleKeyPress(evt.key); break; case SDL_KEYUP: mKeyboardListener->keyReleased(evt.key); @@ -228,4 +232,23 @@ namespace MWInput warpMouse(width / 2, height / 2); } } + + void MWSDLInputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) + { + //SDL keyboard events are followed by the actual text those keys would generate + //to account for languages that require multiple keystrokes to produce a key. + //Look for an event immediately following ours, assuming each key produces exactly + //one character. + + //TODO: This won't work for multibyte characters, but MyGUI is the only consumer + //of these, does it even support multibyte characters? + + SDL_Event text_evts[1]; + if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) + { + evt.keysym.unicode = text_evts[0].text.text[0]; + } + + mKeyboardListener->keyPressed(evt); + } } diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp index c2770ae7e..6377d0bcf 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -30,6 +30,8 @@ namespace MWInput bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); void _wrapMousePointer(const SDL_MouseMotionEvent &evt); + void _handleKeyPress(SDL_KeyboardEvent& evt); + bool _start(); ICS::MWSDLMouseListener* mMouseListener; From ed644259ce71df3a3c61e54d8f92ebf6bfedfe14 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Thu, 10 Jan 2013 17:21:47 -0400 Subject: [PATCH 009/817] Move SDL helpers to their own package in extern/, allow conversion from sdl to ois keycodes, (maybe) fix unicode handling --- CMakeLists.txt | 1 + apps/openmw/CMakeLists.txt | 3 +- apps/openmw/mwinput/inputmanagerimp.cpp | 76 ++-- apps/openmw/mwinput/inputmanagerimp.hpp | 15 +- apps/openmw/mwinput/sdlinputwrapper.cpp | 254 ----------- apps/openmw/mwinput/sdlinputwrapper.hpp | 53 --- extern/oics/CMakeLists.txt | 1 - extern/oics/ICSInputControlSystem.h | 10 +- extern/oics/ICSInputControlSystem_mouse.cpp | 2 +- extern/sdl4ogre/CMakeLists.txt | 14 + extern/sdl4ogre/OISCompat.h | 159 +++++++ .../{oics/OISCompat.h => sdl4ogre/events.h} | 66 +-- extern/sdl4ogre/sdlinputwrapper.cpp | 420 ++++++++++++++++++ extern/sdl4ogre/sdlinputwrapper.hpp | 67 +++ 14 files changed, 733 insertions(+), 408 deletions(-) delete mode 100644 apps/openmw/mwinput/sdlinputwrapper.cpp delete mode 100644 apps/openmw/mwinput/sdlinputwrapper.hpp create mode 100644 extern/sdl4ogre/CMakeLists.txt create mode 100644 extern/sdl4ogre/OISCompat.h rename extern/{oics/OISCompat.h => sdl4ogre/events.h} (53%) create mode 100644 extern/sdl4ogre/sdlinputwrapper.cpp create mode 100644 extern/sdl4ogre/sdlinputwrapper.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index de4be3895..37023571b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -474,6 +474,7 @@ endif(WIN32) # Extern add_subdirectory (extern/shiny) add_subdirectory (extern/oics) +add_subdirectory (extern/sdl4ogre) # Components add_subdirectory (components) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4aa744e3b..faab842c3 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,7 +20,7 @@ add_openmw_dir (mwrender ) add_openmw_dir (mwinput - inputmanagerimp sdlinputwrapper + inputmanagerimp ) add_openmw_dir (mwgui @@ -108,6 +108,7 @@ target_link_libraries(openmw "shiny" "shiny.OgrePlatform" "oics" + "sdl4ogre" components ) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 763e75ae7..6d25f7dc6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -62,13 +62,13 @@ namespace MWInput Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new MWSDLInputWrapper(window); + mInputManager = new SFO::InputWrapper(window); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); std::string file = userFileExists ? userFile : ""; - mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); + mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); adjustMouseRegion (window->getWidth(), window->getHeight()); @@ -78,7 +78,7 @@ namespace MWInput for (int i = 0; i < A_Last; ++i) { - mInputCtrl->getChannel (i)->addListener (this); + mInputBinder->getChannel (i)->addListener (this); } mControlSwitch["playercontrols"] = true; @@ -94,9 +94,9 @@ namespace MWInput InputManager::~InputManager() { - mInputCtrl->save (mUserFile); + mInputBinder->save (mUserFile); - delete mInputCtrl; + delete mInputBinder; delete mInputManager; } @@ -206,7 +206,7 @@ namespace MWInput // update values of channels (as a result of pressed keys) if (!loading) - mInputCtrl->update(dt); + mInputBinder->update(dt); // Update windows/gui as a result of input events // For instance this could mean opening a new window/dialog, @@ -396,12 +396,12 @@ namespace MWInput void InputManager::adjustMouseRegion(int width, int height) { - mInputCtrl->adjustMouseRegion(width, height); + mInputBinder->adjustMouseRegion(width, height); } bool InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { - mInputCtrl->keyPressed (arg); + mInputBinder->keyPressed (arg); unsigned int text = arg.keysym.unicode; //TODO: Check if we need this with SDL @@ -414,23 +414,27 @@ namespace MWInput #endif */ - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.keysym.sym), text); + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); + + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), text); return true; } bool InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { - mInputCtrl->keyReleased (arg); + mInputBinder->keyReleased (arg); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.keysym.sym)); + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); + + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)); return true; } bool InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { - mInputCtrl->mousePressed (arg, id); + mInputBinder->mousePressed (arg, id); MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); @@ -448,16 +452,16 @@ namespace MWInput bool InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) { - mInputCtrl->mouseReleased (arg, id); + mInputBinder->mouseReleased (arg, id); MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); return true; } - bool InputManager::mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ) + bool InputManager::mouseMoved(const SFO::MouseMotionEvent &arg ) { - mInputCtrl->mouseMoved (arg); + mInputBinder->mouseMoved (arg); resetIdleTime (); @@ -683,7 +687,7 @@ namespace MWInput bool InputManager::actionIsActive (int id) { - return mInputCtrl->getChannel (id)->getValue () == 1; + return mInputBinder->getChannel (id)->getValue () == 1; } void InputManager::loadKeyDefaults (bool force) @@ -728,29 +732,29 @@ namespace MWInput for (int i = 0; i < A_Last; ++i) { ICS::Control* control; - bool controlExists = mInputCtrl->getChannel(i)->getControlsCount () != 0; + bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; if (!controlExists) { control = new ICS::Control(boost::lexical_cast(i), false, true, 0, ICS::ICS_MAX, ICS::ICS_MAX); - mInputCtrl->addControl(control); - control->attachChannel(mInputCtrl->getChannel(i), ICS::Channel::DIRECT); + mInputBinder->addControl(control); + control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); } else { - control = mInputCtrl->getChannel(i)->getAttachedControls ().front().control; + control = mInputBinder->getChannel(i)->getAttachedControls ().front().control; } if (!controlExists || force || - ( mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) == SDLK_UNKNOWN - && mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS + ( mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) == SDLK_UNKNOWN + && mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { clearAllBindings (control); if (defaultKeyBindings.find(i) != defaultKeyBindings.end()) - mInputCtrl->addKeyBinding(control, static_cast(defaultKeyBindings[i]), ICS::Control::INCREASE); + mInputBinder->addKeyBinding(control, static_cast(defaultKeyBindings[i]), ICS::Control::INCREASE); else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end()) - mInputCtrl->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); + mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } } } @@ -794,15 +798,15 @@ namespace MWInput std::string InputManager::getActionBindingName (int action) { - if (mInputCtrl->getChannel (action)->getControlsCount () == 0) + if (mInputBinder->getChannel (action)->getControlsCount () == 0) return "#{sNone}"; - ICS::Control* c = mInputCtrl->getChannel (action)->getAttachedControls ().front().control; + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - if (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE) != SDLK_UNKNOWN) - return mInputCtrl->keyCodeToString (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE)); - else if (mInputCtrl->getMouseButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) - return "#{sMouse} " + boost::lexical_cast(mInputCtrl->getMouseButtonBinding (c, ICS::Control::INCREASE)); + if (mInputBinder->getKeyBinding (c, ICS::Control::INCREASE) != SDLK_UNKNOWN) + return mInputBinder->keyCodeToString (mInputBinder->getKeyBinding (c, ICS::Control::INCREASE)); + else if (mInputBinder->getMouseButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + return "#{sMouse} " + boost::lexical_cast(mInputBinder->getMouseButtonBinding (c, ICS::Control::INCREASE)); else return "#{sNone}"; } @@ -842,9 +846,9 @@ namespace MWInput void InputManager::enableDetectingBindingMode (int action) { - ICS::Control* c = mInputCtrl->getChannel (action)->getAttachedControls ().front().control; + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - mInputCtrl->enableDetectingBindingState (c, ICS::Control::INCREASE); + mInputBinder->enableDetectingBindingState (c, ICS::Control::INCREASE); } void InputManager::mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control @@ -905,10 +909,10 @@ namespace MWInput void InputManager::clearAllBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first - if (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) != SDLK_UNKNOWN) - mInputCtrl->removeKeyBinding (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE)); - if (mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) - mInputCtrl->removeMouseButtonBinding (mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE)); + if (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) != SDLK_UNKNOWN) + mInputBinder->removeKeyBinding (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE)); + if (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + mInputBinder->removeMouseButtonBinding (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE)); /// \todo add joysticks here once they are added } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9a7656a67..34ea92a37 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -6,7 +6,7 @@ #include #include "../mwbase/inputmanager.hpp" -#include "sdlinputwrapper.hpp" +#include namespace OEngine { @@ -43,7 +43,6 @@ namespace MyGUI #include #include -#include namespace MWInput { @@ -53,9 +52,9 @@ namespace MWInput */ class InputManager : public MWBase::InputManager, - public ICS::MWSDLKeyListener, - public ICS::MWSDLMouseListener, - public ICS::MWSDLWindowListener, + public SFO::KeyListener, + public SFO::MouseListener, + public SFO::WindowListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { @@ -93,7 +92,7 @@ namespace MWInput virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); - virtual bool mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ); + virtual bool mouseMoved( const SFO::MouseMotionEvent &arg ); virtual bool windowVisibilityChange( bool visible ); virtual bool windowFocusChange( bool have_focus ); @@ -129,10 +128,10 @@ namespace MWInput MWBase::WindowManager &mWindows; OMW::Engine& mEngine; - ICS::InputControlSystem* mInputCtrl; + ICS::InputControlSystem* mInputBinder; - MWSDLInputWrapper* mInputManager; + SFO::InputWrapper* mInputManager; std::string mUserFile; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp deleted file mode 100644 index 56b3568f5..000000000 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include "sdlinputwrapper.hpp" -#include -#include - -#include -#include - -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX -# include -# include -# include -#endif - - -namespace MWInput -{ - MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) : - mWindow(window), - mSDLWindow(NULL), - mWarpCompensate(false), - mMouseRelative(false), - mGrabPointer(false), - mWrapPointer(false) - { - _start(); - } - - MWSDLInputWrapper::~MWSDLInputWrapper() - { - if(mSDLWindow != NULL) - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; - SDL_StopTextInput(); - SDL_Quit(); - } - - bool MWSDLInputWrapper::_start() - { - Uint32 flags = SDL_INIT_VIDEO; - if(SDL_WasInit(flags) == 0) - { - //get the HWND from ogre's renderwindow - size_t windowHnd; - mWindow->getCustomAttribute("WINDOW", &windowHnd); - - //kindly ask SDL not to trash our OGL context - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - if(SDL_Init(SDL_INIT_VIDEO) != 0) - return false; - - //wrap our own event handler around ogre's - mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); - - if(mSDLWindow == NULL) - return false; - - SDL_StartTextInput(); - -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - //linux-specific event-handling fixups - SDL_SysWMinfo wm_info; - SDL_VERSION(&wm_info.version); - - if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) - { - Display* display = wm_info.info.x11.display; - Window w = wm_info.info.x11.window; - - // Set the input hints so we get keyboard input - XWMHints *wmhints = XAllocWMHints(); - if (wmhints) { - wmhints->input = True; - wmhints->flags = InputHint; - XSetWMHints(display, w, wmhints); - XFree(wmhints); - } - - //make sure to subscribe to XLib's events - XSelectInput(display, w, - (FocusChangeMask | EnterWindowMask | LeaveWindowMask | - ExposureMask | ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | KeyPressMask | KeyReleaseMask | - PropertyChangeMask | StructureNotifyMask | - KeymapStateMask)); - - XFlush(display); - } -#endif - SDL_ShowCursor(SDL_FALSE); - } - - return true; - } - - void MWSDLInputWrapper::capture() - { - if(!_start()) - throw std::runtime_error(SDL_GetError()); - - SDL_Event evt; - while(SDL_PollEvent(&evt)) - { - switch(evt.type) - { - case SDL_MOUSEMOTION: - //ignore this if it happened due to a warp - if(!_handleWarpMotion(evt.motion)) - { - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); - - //try to keep the mouse inside the window - _wrapMousePointer(evt.motion); - } - break; - case SDL_MOUSEWHEEL: - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); - break; - case SDL_MOUSEBUTTONDOWN: - mMouseListener->mousePressed(evt.button, evt.button.button); - break; - case SDL_MOUSEBUTTONUP: - mMouseListener->mouseReleased(evt.button, evt.button.button); - break; - - case SDL_KEYDOWN: - _handleKeyPress(evt.key); - break; - case SDL_KEYUP: - mKeyboardListener->keyReleased(evt.key); - break; - - case SDL_WINDOWEVENT_FOCUS_GAINED: - mWindowListener->windowFocusChange(true); - break; - case SDL_WINDOWEVENT_FOCUS_LOST: - mWindowListener->windowFocusChange(false); - break; - case SDL_WINDOWEVENT_EXPOSED: - mWindowListener->windowVisibilityChange(true); - break; - case SDL_WINDOWEVENT_HIDDEN: - mWindowListener->windowVisibilityChange(false); - break; - - //SDL traps ^C signals, pass it to OGRE. - case SDL_QUIT: - Ogre::Root::getSingleton().queueEndRendering(); - break; - } - } - } - - bool MWSDLInputWrapper::isModifierHeld(int mod) - { - return SDL_GetModState() & mod; - } - - void MWSDLInputWrapper::warpMouse(int x, int y) - { - SDL_WarpMouseInWindow(mSDLWindow, x, y); - mWarpCompensate = true; - mWarpX = x; - mWarpY = y; - } - - void MWSDLInputWrapper::setGrabPointer(bool grab) - { - SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; - - mGrabPointer = grab; - SDL_SetWindowGrab(mSDLWindow, sdlGrab); - } - - void MWSDLInputWrapper::setMouseRelative(bool relative) - { - if(mMouseRelative == relative) - return; - - mMouseRelative = relative; - - mWrapPointer = false; - - //eep, wrap the pointer manually if the input driver doesn't support - //relative positioning natively - if(SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == -1) - { - if(relative) - mWrapPointer = true; - } - - //now remove all mouse events using the old setting from the queue - SDL_PumpEvents(); - - SDL_Event dummy[20]; - SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); - } - - bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) - { - if(!mWarpCompensate) - return false; - - //this was a warp event, signal the caller to eat it. - if(evt.x == mWarpX && evt.y == mWarpY) - { - mWarpCompensate = false; - return true; - } - - return false; - } - - void MWSDLInputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) - { - //don't wrap if we don't want relative movements, support relative - //movements natively, or aren't grabbing anyways - if(!mMouseRelative || !mWrapPointer || !mGrabPointer) - return; - - int width = 0; - int height = 0; - - SDL_GetWindowSize(mSDLWindow, &width, &height); - - const int FUDGE_FACTOR_X = width / 4; - const int FUDGE_FACTOR_Y = height / 4; - - //warp the mouse if it's about to go outside the window - if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width - || evt.y - FUDGE_FACTOR_Y < 0 || evt.y + FUDGE_FACTOR_Y > height) - { - warpMouse(width / 2, height / 2); - } - } - - void MWSDLInputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) - { - //SDL keyboard events are followed by the actual text those keys would generate - //to account for languages that require multiple keystrokes to produce a key. - //Look for an event immediately following ours, assuming each key produces exactly - //one character. - - //TODO: This won't work for multibyte characters, but MyGUI is the only consumer - //of these, does it even support multibyte characters? - - SDL_Event text_evts[1]; - if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) - { - evt.keysym.unicode = text_evts[0].text.text[0]; - } - - mKeyboardListener->keyPressed(evt); - } -} diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp deleted file mode 100644 index 6377d0bcf..000000000 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _MWINPUT_SDLINPUTWRAPPER_H -#define _MWINPUT_SDLINPUTWRAPPER_H - -#include "SDL2/SDL_events.h" -#include -#include - - -namespace MWInput -{ - class MWSDLInputWrapper - { - public: - MWSDLInputWrapper(Ogre::RenderWindow* window); - ~MWSDLInputWrapper(); - - void setMouseEventCallback(ICS::MWSDLMouseListener* listen) { mMouseListener = listen; } - void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; } - void setWindowEventCallback(ICS::MWSDLWindowListener* listen) { mWindowListener = listen; } - - void capture(); - bool isModifierHeld(int mod); - - void setMouseRelative(bool relative); - bool getMouseRelative() { return mMouseRelative; } - void setGrabPointer(bool grab); - - void warpMouse(int x, int y); - private: - bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); - void _wrapMousePointer(const SDL_MouseMotionEvent &evt); - - void _handleKeyPress(SDL_KeyboardEvent& evt); - - bool _start(); - - ICS::MWSDLMouseListener* mMouseListener; - ICS::MWSDLKeyListener* mKeyboardListener; - ICS::MWSDLWindowListener* mWindowListener; - - Uint16 mWarpX; - Uint16 mWarpY; - bool mWarpCompensate; - bool mMouseRelative; - bool mWrapPointer; - bool mGrabPointer; - - Ogre::RenderWindow* mWindow; - SDL_Window* mSDLWindow; - }; -} - -#endif diff --git a/extern/oics/CMakeLists.txt b/extern/oics/CMakeLists.txt index 2e2a7a6d6..7c14387a4 100644 --- a/extern/oics/CMakeLists.txt +++ b/extern/oics/CMakeLists.txt @@ -9,7 +9,6 @@ set(OICS_SOURCE_FILES ICSInputControlSystem_keyboard.cpp ICSInputControlSystem_mouse.cpp ICSInputControlSystem_joystick.cpp - OISCompat.h tinyxml.cpp tinyxmlparser.cpp tinyxmlerror.cpp diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 5d30b35cf..f42f9c0b5 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,7 +32,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" -#include "OISCompat.h" +#include "../sdl4ogre/events.h" #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); #define ICS_MAX_JOYSTICK_AXIS 16 @@ -50,9 +50,9 @@ namespace ICS }; class DllExport InputControlSystem : - public MWSDLMouseListener, - public MWSDLKeyListener, - public MWSDLJoyStickListener + public SFO::MouseListener, + public SFO::KeyListener, + public SFO::JoyListener { public: @@ -102,7 +102,7 @@ namespace ICS JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; // MouseListener - bool mouseMoved(const MWSDLMouseMotionEvent &evt); + bool mouseMoved(const SFO::MouseMotionEvent &evt); bool mousePressed(const SDL_MouseButtonEvent &evt, Uint8); bool mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index 96197426a..52eb894ed 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -219,7 +219,7 @@ namespace ICS } // mouse Listeners - bool InputControlSystem::mouseMoved(const MWSDLMouseMotionEvent& evt) + bool InputControlSystem::mouseMoved(const SFO::MouseMotionEvent& evt) { if(mActive) { diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt new file mode 100644 index 000000000..c52dd4cb4 --- /dev/null +++ b/extern/sdl4ogre/CMakeLists.txt @@ -0,0 +1,14 @@ +set(SDL4OGRE_LIBRARY "sdl4ogre") + +# Sources + +set(SDL4OGRE_SOURCE_FILES + sdlinputwrapper.cpp +) + +add_library(${SDL4OGRE_LIBRARY} STATIC ${SDL4OGRE_SOURCE_FILES}) + +link_directories(${CMAKE_CURRENT_BINARY_DIR}) + + +target_link_libraries(${SDL4OGRE_LIBRARY} ${SDL2_LIBRARY}) diff --git a/extern/sdl4ogre/OISCompat.h b/extern/sdl4ogre/OISCompat.h new file mode 100644 index 000000000..04ba2c537 --- /dev/null +++ b/extern/sdl4ogre/OISCompat.h @@ -0,0 +1,159 @@ +#ifndef _OIS_SDL_COMPAT_H +#define _OIS_SDL_COMPAT_H + +#include +#include + +namespace OIS +{ +//! Keyboard scan codes +enum KeyCode +{ + KC_UNASSIGNED = 0x00, + KC_ESCAPE = 0x01, + KC_1 = 0x02, + KC_2 = 0x03, + KC_3 = 0x04, + KC_4 = 0x05, + KC_5 = 0x06, + KC_6 = 0x07, + KC_7 = 0x08, + KC_8 = 0x09, + KC_9 = 0x0A, + KC_0 = 0x0B, + KC_MINUS = 0x0C, // - on main keyboard + KC_EQUALS = 0x0D, + KC_BACK = 0x0E, // backspace + KC_TAB = 0x0F, + KC_Q = 0x10, + KC_W = 0x11, + KC_E = 0x12, + KC_R = 0x13, + KC_T = 0x14, + KC_Y = 0x15, + KC_U = 0x16, + KC_I = 0x17, + KC_O = 0x18, + KC_P = 0x19, + KC_LBRACKET = 0x1A, + KC_RBRACKET = 0x1B, + KC_RETURN = 0x1C, // Enter on main keyboard + KC_LCONTROL = 0x1D, + KC_A = 0x1E, + KC_S = 0x1F, + KC_D = 0x20, + KC_F = 0x21, + KC_G = 0x22, + KC_H = 0x23, + KC_J = 0x24, + KC_K = 0x25, + KC_L = 0x26, + KC_SEMICOLON = 0x27, + KC_APOSTROPHE = 0x28, + KC_GRAVE = 0x29, // accent + KC_LSHIFT = 0x2A, + KC_BACKSLASH = 0x2B, + KC_Z = 0x2C, + KC_X = 0x2D, + KC_C = 0x2E, + KC_V = 0x2F, + KC_B = 0x30, + KC_N = 0x31, + KC_M = 0x32, + KC_COMMA = 0x33, + KC_PERIOD = 0x34, // . on main keyboard + KC_SLASH = 0x35, // / on main keyboard + KC_RSHIFT = 0x36, + KC_MULTIPLY = 0x37, // * on numeric keypad + KC_LMENU = 0x38, // left Alt + KC_SPACE = 0x39, + KC_CAPITAL = 0x3A, + KC_F1 = 0x3B, + KC_F2 = 0x3C, + KC_F3 = 0x3D, + KC_F4 = 0x3E, + KC_F5 = 0x3F, + KC_F6 = 0x40, + KC_F7 = 0x41, + KC_F8 = 0x42, + KC_F9 = 0x43, + KC_F10 = 0x44, + KC_NUMLOCK = 0x45, + KC_SCROLL = 0x46, // Scroll Lock + KC_NUMPAD7 = 0x47, + KC_NUMPAD8 = 0x48, + KC_NUMPAD9 = 0x49, + KC_SUBTRACT = 0x4A, // - on numeric keypad + KC_NUMPAD4 = 0x4B, + KC_NUMPAD5 = 0x4C, + KC_NUMPAD6 = 0x4D, + KC_ADD = 0x4E, // + on numeric keypad + KC_NUMPAD1 = 0x4F, + KC_NUMPAD2 = 0x50, + KC_NUMPAD3 = 0x51, + KC_NUMPAD0 = 0x52, + KC_DECIMAL = 0x53, // . on numeric keypad + KC_OEM_102 = 0x56, // < > | on UK/Germany keyboards + KC_F11 = 0x57, + KC_F12 = 0x58, + KC_F13 = 0x64, // (NEC PC98) + KC_F14 = 0x65, // (NEC PC98) + KC_F15 = 0x66, // (NEC PC98) + KC_KANA = 0x70, // (Japanese keyboard) + KC_ABNT_C1 = 0x73, // / ? on Portugese (Brazilian) keyboards + KC_CONVERT = 0x79, // (Japanese keyboard) + KC_NOCONVERT = 0x7B, // (Japanese keyboard) + KC_YEN = 0x7D, // (Japanese keyboard) + KC_ABNT_C2 = 0x7E, // Numpad . on Portugese (Brazilian) keyboards + KC_NUMPADEQUALS= 0x8D, // = on numeric keypad (NEC PC98) + KC_PREVTRACK = 0x90, // Previous Track (KC_CIRCUMFLEX on Japanese keyboard) + KC_AT = 0x91, // (NEC PC98) + KC_COLON = 0x92, // (NEC PC98) + KC_UNDERLINE = 0x93, // (NEC PC98) + KC_KANJI = 0x94, // (Japanese keyboard) + KC_STOP = 0x95, // (NEC PC98) + KC_AX = 0x96, // (Japan AX) + KC_UNLABELED = 0x97, // (J3100) + KC_NEXTTRACK = 0x99, // Next Track + KC_NUMPADENTER = 0x9C, // Enter on numeric keypad + KC_RCONTROL = 0x9D, + KC_MUTE = 0xA0, // Mute + KC_CALCULATOR = 0xA1, // Calculator + KC_PLAYPAUSE = 0xA2, // Play / Pause + KC_MEDIASTOP = 0xA4, // Media Stop + KC_VOLUMEDOWN = 0xAE, // Volume - + KC_VOLUMEUP = 0xB0, // Volume + + KC_WEBHOME = 0xB2, // Web home + KC_NUMPADCOMMA = 0xB3, // , on numeric keypad (NEC PC98) + KC_DIVIDE = 0xB5, // / on numeric keypad + KC_SYSRQ = 0xB7, + KC_RMENU = 0xB8, // right Alt + KC_PAUSE = 0xC5, // Pause + KC_HOME = 0xC7, // Home on arrow keypad + KC_UP = 0xC8, // UpArrow on arrow keypad + KC_PGUP = 0xC9, // PgUp on arrow keypad + KC_LEFT = 0xCB, // LeftArrow on arrow keypad + KC_RIGHT = 0xCD, // RightArrow on arrow keypad + KC_END = 0xCF, // End on arrow keypad + KC_DOWN = 0xD0, // DownArrow on arrow keypad + KC_PGDOWN = 0xD1, // PgDn on arrow keypad + KC_INSERT = 0xD2, // Insert on arrow keypad + KC_DELETE = 0xD3, // Delete on arrow keypad + KC_LWIN = 0xDB, // Left Windows key + KC_RWIN = 0xDC, // Right Windows key + KC_APPS = 0xDD, // AppMenu key + KC_POWER = 0xDE, // System Power + KC_SLEEP = 0xDF, // System Sleep + KC_WAKE = 0xE3, // System Wake + KC_WEBSEARCH = 0xE5, // Web Search + KC_WEBFAVORITES= 0xE6, // Web Favorites + KC_WEBREFRESH = 0xE7, // Web Refresh + KC_WEBSTOP = 0xE8, // Web Stop + KC_WEBFORWARD = 0xE9, // Web Forward + KC_WEBBACK = 0xEA, // Web Back + KC_MYCOMPUTER = 0xEB, // My Computer + KC_MAIL = 0xEC, // Mail + KC_MEDIASELECT = 0xED // Media Select +}; +} +#endif diff --git a/extern/oics/OISCompat.h b/extern/sdl4ogre/events.h similarity index 53% rename from extern/oics/OISCompat.h rename to extern/sdl4ogre/events.h index 5813c17bf..945daf49a 100644 --- a/extern/oics/OISCompat.h +++ b/extern/sdl4ogre/events.h @@ -1,53 +1,20 @@ -#ifndef _OIS_SDL_COMPAT_H -#define _OIS_SDL_COMPAT_H +#ifndef _SFO_EVENTS_H +#define _SFO_EVENTS_H -#include -#include +#include -//TODO: Remove this. Right now we want to remain as close to OIS as possible -//So we can easily test the SDL backend //////////// // Events // //////////// -namespace ICS { +namespace SFO { /** Extended mouse event struct where we treat the wheel like an axis, like everyone expects */ -struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { +struct MouseMotionEvent : SDL_MouseMotionEvent { - Sint16 zrel; - - MWSDLMouseMotionEvent() - { - _init(); - } - - MWSDLMouseMotionEvent( const SDL_MouseMotionEvent& evt) - { - _init(); - x = evt.x; - y = evt.y; - xrel = evt.xrel; - yrel = evt.yrel; - state = evt.state; - } - - MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) - { - _init(); - zrel = evt.y; - } - - void _init() - { - x = 0; - y = 0; - xrel = 0; - yrel = 0; - state = 0; - zrel = 0; - } + Sint32 zrel; + Sint32 z; }; @@ -55,27 +22,27 @@ struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { // Listeners // /////////////// -class MWSDLMouseListener +class MouseListener { public: - virtual ~MWSDLMouseListener() {} - virtual bool mouseMoved( const MWSDLMouseMotionEvent &arg ) = 0; + virtual ~MouseListener() {} + virtual bool mouseMoved( const MouseMotionEvent &arg ) = 0; virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) = 0; virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) = 0; }; -class MWSDLKeyListener +class KeyListener { public: - virtual ~MWSDLKeyListener() {} + virtual ~KeyListener() {} virtual bool keyPressed(const SDL_KeyboardEvent &arg) = 0; virtual bool keyReleased(const SDL_KeyboardEvent &arg) = 0; }; -class MWSDLJoyStickListener +class JoyListener { public: - virtual ~MWSDLJoyStickListener() {} + virtual ~JoyListener() {} /** @remarks Joystick button down event */ virtual bool buttonPressed( const SDL_JoyButtonEvent &evt, int button ) = 0; @@ -91,10 +58,10 @@ public: virtual bool povMoved( const SDL_JoyHatEvent &arg, int index) {return true;} }; -class MWSDLWindowListener +class WindowListener { public: - virtual ~MWSDLWindowListener() {} + virtual ~WindowListener() {} /** @remarks The window's visibility changed */ virtual bool windowVisibilityChange( bool visible ) = 0; @@ -104,4 +71,5 @@ public: }; } + #endif diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp new file mode 100644 index 000000000..b7d1550c9 --- /dev/null +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -0,0 +1,420 @@ +#include "sdlinputwrapper.hpp" +#include + +#include +#include +#include + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +# include +# include +# include +#endif + + +namespace SFO +{ + InputWrapper::InputWrapper(Ogre::RenderWindow *window) : + mWindow(window), + mSDLWindow(NULL), + mWarpCompensate(false), + mMouseRelative(false), + mGrabPointer(false), + mWrapPointer(false), + mMouseZ(0), + mMouseY(0), + mMouseX(0) + { + _start(); + _setupOISKeys(); + } + + InputWrapper::~InputWrapper() + { + if(mSDLWindow != NULL) + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + SDL_StopTextInput(); + SDL_Quit(); + } + + bool InputWrapper::_start() + { + Uint32 flags = SDL_INIT_VIDEO; + if(SDL_WasInit(flags) == 0) + { + //get the HWND from ogre's renderwindow + size_t windowHnd; + mWindow->getCustomAttribute("WINDOW", &windowHnd); + + //kindly ask SDL not to trash our OGL context + //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + if(SDL_Init(SDL_INIT_VIDEO) != 0) + return false; + + //wrap our own event handler around ogre's + mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + + if(mSDLWindow == NULL) + return false; + + SDL_StartTextInput(); + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX + //linux-specific event-handling fixups + //see http://bugzilla.libsdl.org/show_bug.cgi?id=730 + SDL_SysWMinfo wm_info; + SDL_VERSION(&wm_info.version); + + if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) + { + Display* display = wm_info.info.x11.display; + Window w = wm_info.info.x11.window; + + // Set the input hints so we get keyboard input + XWMHints *wmhints = XAllocWMHints(); + if (wmhints) { + wmhints->input = True; + wmhints->flags = InputHint; + XSetWMHints(display, w, wmhints); + XFree(wmhints); + } + + //make sure to subscribe to XLib's events + XSelectInput(display, w, + (FocusChangeMask | EnterWindowMask | LeaveWindowMask | + ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | KeyPressMask | KeyReleaseMask | + PropertyChangeMask | StructureNotifyMask | + KeymapStateMask)); + + XFlush(display); + } +#endif + SDL_ShowCursor(SDL_FALSE); + } + + return true; + } + + void InputWrapper::capture() + { + if(!_start()) + throw std::runtime_error(SDL_GetError()); + + SDL_Event evt; + while(SDL_PollEvent(&evt)) + { + switch(evt.type) + { + case SDL_MOUSEMOTION: + //ignore this if it happened due to a warp + if(!_handleWarpMotion(evt.motion)) + { + mMouseListener->mouseMoved(_packageMouseMotion(evt)); + + //try to keep the mouse inside the window + _wrapMousePointer(evt.motion); + } + break; + case SDL_MOUSEWHEEL: + mMouseListener->mouseMoved(_packageMouseMotion(evt)); + break; + case SDL_MOUSEBUTTONDOWN: + mMouseListener->mousePressed(evt.button, evt.button.button); + break; + case SDL_MOUSEBUTTONUP: + mMouseListener->mouseReleased(evt.button, evt.button.button); + break; + + case SDL_KEYDOWN: + _handleKeyPress(evt.key); + break; + case SDL_KEYUP: + mKeyboardListener->keyReleased(evt.key); + break; + + case SDL_WINDOWEVENT_FOCUS_GAINED: + mWindowListener->windowFocusChange(true); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + mWindowListener->windowFocusChange(false); + break; + case SDL_WINDOWEVENT_EXPOSED: + mWindowListener->windowVisibilityChange(true); + break; + case SDL_WINDOWEVENT_HIDDEN: + mWindowListener->windowVisibilityChange(false); + break; + + //SDL traps ^C signals, pass it to OGRE. + case SDL_QUIT: + Ogre::Root::getSingleton().queueEndRendering(); + break; + } + } + } + + bool InputWrapper::isModifierHeld(int mod) + { + return SDL_GetModState() & mod; + } + + void InputWrapper::warpMouse(int x, int y) + { + SDL_WarpMouseInWindow(mSDLWindow, x, y); + mWarpCompensate = true; + mWarpX = x; + mWarpY = y; + } + + void InputWrapper::setGrabPointer(bool grab) + { + SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; + + mGrabPointer = grab; + SDL_SetWindowGrab(mSDLWindow, sdlGrab); + } + + void InputWrapper::setMouseRelative(bool relative) + { + if(mMouseRelative == relative) + return; + + mMouseRelative = relative; + + mWrapPointer = false; + + //eep, wrap the pointer manually if the input driver doesn't support + //relative positioning natively + if(SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == -1) + { + if(relative) + mWrapPointer = true; + } + + //now remove all mouse events using the old setting from the queue + SDL_PumpEvents(); + + SDL_Event dummy[20]; + SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); + } + + bool InputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) + { + if(!mWarpCompensate) + return false; + + //this was a warp event, signal the caller to eat it. + if(evt.x == mWarpX && evt.y == mWarpY) + { + mWarpCompensate = false; + return true; + } + + return false; + } + + void InputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) + { + //don't wrap if we don't want relative movements, support relative + //movements natively, or aren't grabbing anyways + if(!mMouseRelative || !mWrapPointer || !mGrabPointer) + return; + + int width = 0; + int height = 0; + + SDL_GetWindowSize(mSDLWindow, &width, &height); + + const int FUDGE_FACTOR_X = width / 4; + const int FUDGE_FACTOR_Y = height / 4; + + //warp the mouse if it's about to go outside the window + if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width + || evt.y - FUDGE_FACTOR_Y < 0 || evt.y + FUDGE_FACTOR_Y > height) + { + warpMouse(width / 2, height / 2); + } + } + + void InputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) + { + //SDL keyboard events are followed by the actual text those keys would generate + //to account for languages that require multiple keystrokes to produce a key. + //Look for an event immediately following ours, assuming each key produces exactly + //one character or none at all. + + //TODO: Check if this works properly for multibyte symbols + //do we have to worry about endian-ness? + //for that matter, check if we even need to do any of this. + + SDL_Event text_evts[1]; + if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) + { + const char* symbol = text_evts[0].text.text; + + Uint32 num_bytes = strlen(symbol); + + //no valid character is more than 4 bytes + if(num_bytes > 0 && num_bytes <= 4) + { + Uint32 u32_symbol = boost::locale::conv::utf_to_utf(symbol)[0]; + + evt.keysym.unicode = u32_symbol; + } + } + + mKeyboardListener->keyPressed(evt); + } + + MouseMotionEvent InputWrapper::_packageMouseMotion(const SDL_Event &evt) + { + MouseMotionEvent pack_evt; + pack_evt.x = mMouseX; + pack_evt.xrel = 0; + pack_evt.y = mMouseY; + pack_evt.yrel = 0; + pack_evt.z = mMouseZ; + pack_evt.zrel = 0; + + if(evt.type == SDL_MOUSEMOTION) + { + pack_evt.x = mMouseX = evt.motion.x; + pack_evt.y = mMouseY = evt.motion.y; + pack_evt.xrel = evt.motion.xrel; + pack_evt.yrel = evt.motion.yrel; + } + else if(evt.type == SDL_MOUSEWHEEL) + { + mMouseZ += pack_evt.zrel = evt.wheel.y; + pack_evt.z = mMouseZ; + } + else + { + throw new std::runtime_error("Tried to package non-motion event!"); + } + + return pack_evt; + } + + OIS::KeyCode InputWrapper::sdl2OISKeyCode(SDL_Keycode code) + { + OIS::KeyCode kc = OIS::KC_UNASSIGNED; + + KeyMap::const_iterator ois_equiv = mKeyMap.find(code); + + if(ois_equiv != mKeyMap.end()) + kc = ois_equiv->second; + + return kc; + } + + void InputWrapper::_setupOISKeys() + { + //lifted from OIS's SDLKeyboard.cpp + mKeyMap.insert( KeyMap::value_type(SDLK_UNKNOWN, OIS::KC_UNASSIGNED)); + mKeyMap.insert( KeyMap::value_type(SDLK_ESCAPE, OIS::KC_ESCAPE) ); + mKeyMap.insert( KeyMap::value_type(SDLK_1, OIS::KC_1) ); + mKeyMap.insert( KeyMap::value_type(SDLK_2, OIS::KC_2) ); + mKeyMap.insert( KeyMap::value_type(SDLK_3, OIS::KC_3) ); + mKeyMap.insert( KeyMap::value_type(SDLK_4, OIS::KC_4) ); + mKeyMap.insert( KeyMap::value_type(SDLK_5, OIS::KC_5) ); + mKeyMap.insert( KeyMap::value_type(SDLK_6, OIS::KC_6) ); + mKeyMap.insert( KeyMap::value_type(SDLK_7, OIS::KC_7) ); + mKeyMap.insert( KeyMap::value_type(SDLK_8, OIS::KC_8) ); + mKeyMap.insert( KeyMap::value_type(SDLK_9, OIS::KC_9) ); + mKeyMap.insert( KeyMap::value_type(SDLK_0, OIS::KC_0) ); + mKeyMap.insert( KeyMap::value_type(SDLK_MINUS, OIS::KC_MINUS) ); + mKeyMap.insert( KeyMap::value_type(SDLK_EQUALS, OIS::KC_EQUALS) ); + mKeyMap.insert( KeyMap::value_type(SDLK_BACKSPACE, OIS::KC_BACK) ); + mKeyMap.insert( KeyMap::value_type(SDLK_TAB, OIS::KC_TAB) ); + mKeyMap.insert( KeyMap::value_type(SDLK_q, OIS::KC_Q) ); + mKeyMap.insert( KeyMap::value_type(SDLK_w, OIS::KC_W) ); + mKeyMap.insert( KeyMap::value_type(SDLK_e, OIS::KC_E) ); + mKeyMap.insert( KeyMap::value_type(SDLK_r, OIS::KC_R) ); + mKeyMap.insert( KeyMap::value_type(SDLK_t, OIS::KC_T) ); + mKeyMap.insert( KeyMap::value_type(SDLK_y, OIS::KC_Y) ); + mKeyMap.insert( KeyMap::value_type(SDLK_u, OIS::KC_U) ); + mKeyMap.insert( KeyMap::value_type(SDLK_i, OIS::KC_I) ); + mKeyMap.insert( KeyMap::value_type(SDLK_o, OIS::KC_O) ); + mKeyMap.insert( KeyMap::value_type(SDLK_p, OIS::KC_P) ); + mKeyMap.insert( KeyMap::value_type(SDLK_RETURN, OIS::KC_RETURN) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LCONTROL)); + mKeyMap.insert( KeyMap::value_type(SDLK_a, OIS::KC_A) ); + mKeyMap.insert( KeyMap::value_type(SDLK_s, OIS::KC_S) ); + mKeyMap.insert( KeyMap::value_type(SDLK_d, OIS::KC_D) ); + mKeyMap.insert( KeyMap::value_type(SDLK_f, OIS::KC_F) ); + mKeyMap.insert( KeyMap::value_type(SDLK_g, OIS::KC_G) ); + mKeyMap.insert( KeyMap::value_type(SDLK_h, OIS::KC_H) ); + mKeyMap.insert( KeyMap::value_type(SDLK_j, OIS::KC_J) ); + mKeyMap.insert( KeyMap::value_type(SDLK_k, OIS::KC_K) ); + mKeyMap.insert( KeyMap::value_type(SDLK_l, OIS::KC_L) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SEMICOLON, OIS::KC_SEMICOLON) ); + mKeyMap.insert( KeyMap::value_type(SDLK_COLON, OIS::KC_COLON) ); + mKeyMap.insert( KeyMap::value_type(SDLK_QUOTE, OIS::KC_APOSTROPHE) ); + mKeyMap.insert( KeyMap::value_type(SDLK_BACKQUOTE, OIS::KC_GRAVE) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LSHIFT, OIS::KC_LSHIFT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_BACKSLASH, OIS::KC_BACKSLASH) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SLASH, OIS::KC_SLASH) ); + mKeyMap.insert( KeyMap::value_type(SDLK_z, OIS::KC_Z) ); + mKeyMap.insert( KeyMap::value_type(SDLK_x, OIS::KC_X) ); + mKeyMap.insert( KeyMap::value_type(SDLK_c, OIS::KC_C) ); + mKeyMap.insert( KeyMap::value_type(SDLK_v, OIS::KC_V) ); + mKeyMap.insert( KeyMap::value_type(SDLK_b, OIS::KC_B) ); + mKeyMap.insert( KeyMap::value_type(SDLK_n, OIS::KC_N) ); + mKeyMap.insert( KeyMap::value_type(SDLK_m, OIS::KC_M) ); + mKeyMap.insert( KeyMap::value_type(SDLK_COMMA, OIS::KC_COMMA) ); + mKeyMap.insert( KeyMap::value_type(SDLK_PERIOD, OIS::KC_PERIOD)); + mKeyMap.insert( KeyMap::value_type(SDLK_RSHIFT, OIS::KC_RSHIFT)); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_MULTIPLY, OIS::KC_MULTIPLY) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LALT, OIS::KC_LMENU) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SPACE, OIS::KC_SPACE)); + mKeyMap.insert( KeyMap::value_type(SDLK_CAPSLOCK, OIS::KC_CAPITAL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F1, OIS::KC_F1) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F2, OIS::KC_F2) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F3, OIS::KC_F3) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F4, OIS::KC_F4) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F5, OIS::KC_F5) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F6, OIS::KC_F6) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F7, OIS::KC_F7) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F8, OIS::KC_F8) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F9, OIS::KC_F9) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F10, OIS::KC_F10) ); + mKeyMap.insert( KeyMap::value_type(SDLK_NUMLOCKCLEAR, OIS::KC_NUMLOCK) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SCROLLLOCK, OIS::KC_SCROLL)); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_7, OIS::KC_NUMPAD7) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_8, OIS::KC_NUMPAD8) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_9, OIS::KC_NUMPAD9) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_MINUS, OIS::KC_SUBTRACT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_4, OIS::KC_NUMPAD4) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_5, OIS::KC_NUMPAD5) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_6, OIS::KC_NUMPAD6) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_PLUS, OIS::KC_ADD) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_1, OIS::KC_NUMPAD1) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_2, OIS::KC_NUMPAD2) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_3, OIS::KC_NUMPAD3) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_0, OIS::KC_NUMPAD0) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_PERIOD, OIS::KC_DECIMAL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F11, OIS::KC_F11) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F12, OIS::KC_F12) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F13, OIS::KC_F13) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F14, OIS::KC_F14) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F15, OIS::KC_F15) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_EQUALS, OIS::KC_NUMPADEQUALS) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_DIVIDE, OIS::KC_DIVIDE) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SYSREQ, OIS::KC_SYSRQ) ); + mKeyMap.insert( KeyMap::value_type(SDLK_RALT, OIS::KC_RMENU) ); + mKeyMap.insert( KeyMap::value_type(SDLK_HOME, OIS::KC_HOME) ); + mKeyMap.insert( KeyMap::value_type(SDLK_UP, OIS::KC_UP) ); + mKeyMap.insert( KeyMap::value_type(SDLK_PAGEUP, OIS::KC_PGUP) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LEFT, OIS::KC_LEFT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_RIGHT, OIS::KC_RIGHT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_END, OIS::KC_END) ); + mKeyMap.insert( KeyMap::value_type(SDLK_DOWN, OIS::KC_DOWN) ); + mKeyMap.insert( KeyMap::value_type(SDLK_PAGEDOWN, OIS::KC_PGDOWN) ); + mKeyMap.insert( KeyMap::value_type(SDLK_INSERT, OIS::KC_INSERT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_DELETE, OIS::KC_DELETE) ); + } +} diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp new file mode 100644 index 000000000..63b4c922b --- /dev/null +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -0,0 +1,67 @@ +#ifndef _MWINPUT_SDLINPUTWRAPPER_H +#define _MWINPUT_SDLINPUTWRAPPER_H + +#include "SDL2/SDL_events.h" +#include +#include + +#include "OISCompat.h" +#include "events.h" + + +namespace SFO +{ + class InputWrapper + { + public: + InputWrapper(Ogre::RenderWindow* window); + ~InputWrapper(); + + void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } + void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } + void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } + + void capture(); + bool isModifierHeld(int mod); + + void setMouseRelative(bool relative); + bool getMouseRelative() { return mMouseRelative; } + void setGrabPointer(bool grab); + + OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code); + + void warpMouse(int x, int y); + private: + bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); + void _wrapMousePointer(const SDL_MouseMotionEvent &evt); + + MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); + void _handleKeyPress(SDL_KeyboardEvent& evt); + + bool _start(); + void _setupOISKeys(); + + SFO::MouseListener* mMouseListener; + SFO::KeyListener* mKeyboardListener; + SFO::WindowListener* mWindowListener; + + typedef boost::unordered::unordered_map KeyMap; + KeyMap mKeyMap; + + Uint16 mWarpX; + Uint16 mWarpY; + bool mWarpCompensate; + bool mMouseRelative; + bool mWrapPointer; + bool mGrabPointer; + + Sint32 mMouseZ; + Sint32 mMouseX; + Sint32 mMouseY; + + Ogre::RenderWindow* mWindow; + SDL_Window* mSDLWindow; + }; +} + +#endif From 601d79ef3f83d741d1913911845863037000690b Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Thu, 10 Jan 2013 17:59:49 -0400 Subject: [PATCH 010/817] fix the mouse wheel in mygui --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +-- extern/sdl4ogre/sdlinputwrapper.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6d25f7dc6..308065e7e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -487,8 +487,7 @@ namespace MWInput mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); - //there's no such thing as an absolute z position, so let's keep track of it ourselves - mMouseWheel += arg.zrel; + mMouseWheel = int(arg.z); MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index b7d1550c9..93f00d4b5 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -288,7 +288,7 @@ namespace SFO } else if(evt.type == SDL_MOUSEWHEEL) { - mMouseZ += pack_evt.zrel = evt.wheel.y; + mMouseZ += pack_evt.zrel = (evt.wheel.y * 120); pack_evt.z = mMouseZ; } else From 403b6756f516cb700c2f033890947070b29892c9 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Thu, 10 Jan 2013 23:29:51 -0400 Subject: [PATCH 011/817] remove dependency on boost::locale, use system mouse position in in-game menus --- apps/openmw/mwinput/inputmanagerimp.cpp | 21 ++--- extern/sdl4ogre/sdlinputwrapper.cpp | 105 +++++++++++++++++------- extern/sdl4ogre/sdlinputwrapper.hpp | 7 +- 3 files changed, 86 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 308065e7e..358eb7b92 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -221,9 +221,10 @@ namespace MWInput bool main_menu = mWindows.containsMode(MWGui::GM_MainMenu); bool was_relative = mInputManager->getMouseRelative(); - bool is_relative = !main_menu; + bool is_relative = !mWindows.isGuiMode(); - //don't keep the pointer away from the window edge in the main menu + // don't keep the pointer away from the window edge in gui mode + // stop using raw mouse motions and switch to system cursor movements mInputManager->setMouseRelative(is_relative); //we switched to non-relative mode, move our cursor to where the in-game @@ -472,17 +473,11 @@ namespace MWInput // 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 - //FIXME: Except in the main menu, since we let the pointer escape - if(!mWindows.containsMode(MWGui::GM_MainMenu)) - { - mMouseX += float(arg.xrel) * mUISensitivity; - mMouseY += float(arg.yrel) * mUISensitivity * mUIYMultiplier; - } - else - { - mMouseX = arg.x; - mMouseY = arg.y; - } + // Don't support the UI sensitivity slider to reduce headache + // related to when the mouse can leave the window, and what to + // do when it re-enters + mMouseX = arg.x; + mMouseY = arg.y; mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 93f00d4b5..a198542c7 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -3,7 +3,6 @@ #include #include -#include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX # include @@ -239,36 +238,6 @@ namespace SFO } } - void InputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) - { - //SDL keyboard events are followed by the actual text those keys would generate - //to account for languages that require multiple keystrokes to produce a key. - //Look for an event immediately following ours, assuming each key produces exactly - //one character or none at all. - - //TODO: Check if this works properly for multibyte symbols - //do we have to worry about endian-ness? - //for that matter, check if we even need to do any of this. - - SDL_Event text_evts[1]; - if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) - { - const char* symbol = text_evts[0].text.text; - - Uint32 num_bytes = strlen(symbol); - - //no valid character is more than 4 bytes - if(num_bytes > 0 && num_bytes <= 4) - { - Uint32 u32_symbol = boost::locale::conv::utf_to_utf(symbol)[0]; - - evt.keysym.unicode = u32_symbol; - } - } - - mKeyboardListener->keyPressed(evt); - } - MouseMotionEvent InputWrapper::_packageMouseMotion(const SDL_Event &evt) { MouseMotionEvent pack_evt; @@ -299,6 +268,74 @@ namespace SFO return pack_evt; } + void InputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) + { + //SDL keyboard events are followed by the actual text those keys would generate + //to account for languages that require multiple keystrokes to produce a key. + //Look for an event immediately following ours, assuming each key produces exactly + //one character or none at all. + + //TODO: Check if this works properly for multibyte symbols + //do we have to worry about endian-ness? + //for that matter, check if we even need to do any of this. + + SDL_Event text_evts[1]; + if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) + { + if(strlen(text_evts[0].text.text) != 0) + { + const unsigned char* symbol = reinterpret_cast(&(text_evts[0].text.text[0])); + evt.keysym.unicode = _UTF8ToUTF32(symbol); + } + } + + mKeyboardListener->keyPressed(evt); + } + + //Lifted from OIS' LinuxKeyboard.cpp + Uint32 InputWrapper::_UTF8ToUTF32(const unsigned char *buf) + { + unsigned char FirstChar = buf[0]; + + //it's an ascii char, bail out early. + if(FirstChar < 128) + return FirstChar; + + Uint32 val = 0; + Sint32 len = 0; + + if((FirstChar & 0xE0) == 0xC0) //2 Chars + { + len = 2; + val = FirstChar & 0x1F; + } + else if((FirstChar & 0xF0) == 0xE0) //3 Chars + { + len = 3; + val = FirstChar & 0x0F; + } + else if((FirstChar & 0xF8) == 0xF0) //4 Chars + { + len = 4; + val = FirstChar & 0x07; + } + else if((FirstChar & 0xFC) == 0xF8) //5 Chars + { + len = 5; + val = FirstChar & 0x03; + } + else // if((FirstChar & 0xFE) == 0xFC) //6 Chars + { + len = 6; + val = FirstChar & 0x01; + } + + for(int i = 1; i < len; i++) + val = (val << 6) | (buf[i] & 0x3F); + + return val; + } + OIS::KeyCode InputWrapper::sdl2OISKeyCode(SDL_Keycode code) { OIS::KeyCode kc = OIS::KC_UNASSIGNED; @@ -307,6 +344,8 @@ namespace SFO if(ois_equiv != mKeyMap.end()) kc = ois_equiv->second; + else + std::cerr << "Couldn't find OIS key for " << SDLK_SYSREQ << std::endl; return kc; } @@ -314,6 +353,10 @@ namespace SFO void InputWrapper::_setupOISKeys() { //lifted from OIS's SDLKeyboard.cpp + + //TODO: Consider switching to scancodes so we + //can properly support international keyboards + //look at SDL_GetKeyFromScancode and SDL_GetKeyName mKeyMap.insert( KeyMap::value_type(SDLK_UNKNOWN, OIS::KC_UNASSIGNED)); mKeyMap.insert( KeyMap::value_type(SDLK_ESCAPE, OIS::KC_ESCAPE) ); mKeyMap.insert( KeyMap::value_type(SDLK_1, OIS::KC_1) ); diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 63b4c922b..55c45316f 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -32,13 +32,14 @@ namespace SFO void warpMouse(int x, int y); private: + bool _start(); + bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); void _wrapMousePointer(const SDL_MouseMotionEvent &evt); - MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); - void _handleKeyPress(SDL_KeyboardEvent& evt); - bool _start(); + void _handleKeyPress(SDL_KeyboardEvent& evt); + Uint32 _UTF8ToUTF32(const unsigned char *buf); void _setupOISKeys(); SFO::MouseListener* mMouseListener; From a030c035133d4fcbad08272bb33997adfd45580c Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Thu, 10 Jan 2013 23:53:19 -0400 Subject: [PATCH 012/817] support the printscreen button properly --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- extern/oics/ICSInputControlSystem.cpp | 1 + extern/sdl4ogre/sdlinputwrapper.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 358eb7b92..7785167f8 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -716,7 +716,7 @@ namespace MWInput defaultKeyBindings[A_QuickKey8] = SDLK_8; defaultKeyBindings[A_QuickKey9] = SDLK_9; defaultKeyBindings[A_QuickKey10] = SDLK_0; - defaultKeyBindings[A_Screenshot] = SDLK_SYSREQ; + defaultKeyBindings[A_Screenshot] = SDLK_PRINTSCREEN; defaultKeyBindings[A_ToggleHUD] = SDLK_F12; std::map defaultMouseButtonBindings; diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 159b3241f..cdf8fbfe2 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -892,6 +892,7 @@ namespace ICS mKeys["RCONTROL"]= SDLK_RCTRL; mKeys["DIVIDE"]= SDLK_SLASH; mKeys["SYSRQ"]= SDLK_SYSREQ; + mKeys["PRNTSCRN"] = SDLK_PRINTSCREEN; mKeys["RMENU"]= SDLK_RALT; mKeys["PAUSE"]= SDLK_PAUSE; mKeys["HOME"]= SDLK_HOME; diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index a198542c7..e194719cb 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -345,7 +345,7 @@ namespace SFO if(ois_equiv != mKeyMap.end()) kc = ois_equiv->second; else - std::cerr << "Couldn't find OIS key for " << SDLK_SYSREQ << std::endl; + std::cerr << "Couldn't find OIS key for " << code << std::endl; return kc; } From 1117105039768175d517a758f216ad1cb0d8c992 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 11 Jan 2013 00:37:04 -0400 Subject: [PATCH 013/817] fix compile error with boost includes --- extern/sdl4ogre/sdlinputwrapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 55c45316f..eba2ed8d0 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -46,7 +46,7 @@ namespace SFO SFO::KeyListener* mKeyboardListener; SFO::WindowListener* mWindowListener; - typedef boost::unordered::unordered_map KeyMap; + typedef boost::unordered_map KeyMap; KeyMap mKeyMap; Uint16 mWarpX; From f9b064d1bc17699558b2298eb35ed271cf43b8e6 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 11 Jan 2013 08:27:59 -0400 Subject: [PATCH 014/817] add preliminary hardware cursor support into sdl4ogre and windowmanagerimp, handle alt-tabbing away from fullscreen gracefully --- apps/openmw/mwbase/windowmanager.hpp | 7 ++ apps/openmw/mwgui/cursorreplace.cpp | 64 +++++++++++ apps/openmw/mwgui/cursorreplace.hpp | 35 +++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 51 +++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 11 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 2 + extern/sdl4ogre/sdlinputwrapper.cpp | 134 +++++++++++++++++++++++- extern/sdl4ogre/sdlinputwrapper.hpp | 35 ++++++- 8 files changed, 334 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 13a35b592..e7a63a1b5 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -55,6 +55,11 @@ namespace MWGui class DialogueWindow; } +namespace SFO +{ + class CursorChangeClient; +} + namespace MWBase { /// \brief Interface for widnow manager (implemented in MWGui) @@ -238,6 +243,8 @@ namespace MWBase virtual void startTraining(MWWorld::Ptr actor) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; + + virtual void setCursorChangeClient(SFO::CursorChangeClient* client) = 0; }; } diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp index 2079538fc..f883a4ed7 100644 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ b/apps/openmw/mwgui/cursorreplace.cpp @@ -5,9 +5,73 @@ #include #include +#include using namespace MWGui; + +#include "MyGUI_Precompiled.h" +#include "MyGUI_ResourceImageSetPointer.h" +#include "MyGUI_ImageBox.h" +#include "MyGUI_ResourceManager.h" + + + + ResourceImageSetPointerFix::ResourceImageSetPointerFix() : + mImageSet(nullptr) + { + } + + ResourceImageSetPointerFix::~ResourceImageSetPointerFix() + { + } + + void ResourceImageSetPointerFix::deserialization(xml::ElementPtr _node, Version _version) + { + Base::deserialization(_node, _version); + + // берем детей и крутимся, основной цикл + xml::ElementEnumerator info = _node->getElementEnumerator(); + while (info.next("Property")) + { + const std::string& key = info->findAttribute("key"); + const std::string& value = info->findAttribute("value"); + + if (key == "Point") + mPoint = IntPoint::parse(value); + else if (key == "Size") + mSize = IntSize::parse(value); + else if (key == "Resource") + mImageSet = ResourceManager::getInstance().getByName(value)->castType(); + } + } + + void ResourceImageSetPointerFix::setImage(ImageBox* _image) + { + if (mImageSet != nullptr) + _image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0)); + } + + void ResourceImageSetPointerFix::setPosition(ImageBox* _image, const IntPoint& _point) + { + _image->setCoord(_point.left - mPoint.left, _point.top - mPoint.top, mSize.width, mSize.height); + } + + ResourceImageSetPtr ResourceImageSetPointerFix:: getImageSet() + { + return mImageSet; + } + + IntPoint ResourceImageSetPointerFix::getHotSpot() + { + return mPoint; + } + + IntSize ResourceImageSetPointerFix::getSize() + { + return mSize; + } + CursorReplace::CursorReplace() { OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); diff --git a/apps/openmw/mwgui/cursorreplace.hpp b/apps/openmw/mwgui/cursorreplace.hpp index 06fe28e39..402eda1ab 100644 --- a/apps/openmw/mwgui/cursorreplace.hpp +++ b/apps/openmw/mwgui/cursorreplace.hpp @@ -2,9 +2,44 @@ #define GAME_CURSORREPLACE_H #include +#include +#include + +using namespace MyGUI; namespace MWGui { + /// \brief A simple class that allows us to get the members of + /// ResourceImageSetPointer that we need. Use with + /// MyGUI + /// \example MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + /// MyGUI::ResourceManager::getInstance().load("core.xml"); + class ResourceImageSetPointerFix : + public IPointer + { + MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix ) + + public: + ResourceImageSetPointerFix(); + virtual ~ResourceImageSetPointerFix(); + + virtual void deserialization(xml::ElementPtr _node, Version _version); + + virtual void setImage(ImageBox* _image); + virtual void setPosition(ImageBox* _image, const IntPoint& _point); + + //and now for the whole point of this class, allow us to get + //the hot spot, the image and the size of the cursor. + virtual ResourceImageSetPtr getImageSet(); + virtual IntPoint getHotSpot(); + virtual IntSize getSize(); + + private: + IntPoint mPoint; + IntSize mSize; + ResourceImageSetPtr mImageSet; + }; + /// \brief MyGUI does not support rotating cursors, so we have to do it manually class CursorReplace { diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d653b578a..7c99d004e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -4,10 +4,15 @@ #include #include "MyGUI_UString.h" +#include "MYGUI/MyGUI_IPointer.h" +#include "MYGUI/MyGUI_ResourceImageSetPointer.h" +#include "MyGUI_TextureUtility.h" #include #include +#include + #include #include @@ -53,6 +58,8 @@ #include "trainingwindow.hpp" #include "imagebutton.hpp" +#include "cursorreplace.hpp" + using namespace MWGui; WindowManager::WindowManager( @@ -108,12 +115,17 @@ WindowManager::WindowManager( , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHudEnabled(true) , mTranslationDataStorage (translationDataStorage) + , mCursorChangeClient(NULL) { // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); mGui = mGuiManager->getGui(); + //Use our own ResourceImageSetPointer class so we can get the texture and hotspot for a pointer + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + MyGUI::ResourceManager::getInstance().load("core.xml"); + //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); @@ -130,6 +142,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); + MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); // Get size info from the Gui object assert(mGui); @@ -758,6 +771,44 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r } } + void WindowManager::setCursorChangeClient(SFO::CursorChangeClient* client) + { + mCursorChangeClient = client; + onCursorChange(PointerManager::getInstance().getDefaultPointer()); + } + +void WindowManager::onCursorChange(const std::string &name) +{ + //we have no client, don't care. + if(!mCursorChangeClient) + return; + + //the client doesn't want any more info about this cursor + if(!mCursorChangeClient->cursorChanged(name)) + return; + //See if we can get the information we need out of the cursor resource + ResourceImageSetPointerFix* imgSetPtr = dynamic_cast(MyGUI::PointerManager::getInstance().getByName(name)); + if(imgSetPtr != NULL) + { + MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet(); + + std::string tex_name = imgSet->getIndexInfo(0,0).texture; + + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName(tex_name); + + //everything looks good, send it to the client + if(!tex.isNull()) + { + Uint8 size_x = imgSetPtr->getSize().width; + Uint8 size_y = imgSetPtr->getSize().height; + Uint8 hotspot_x = imgSetPtr->getHotSpot().left; + Uint8 hotspot_y = imgSetPtr->getHotSpot().top; + + mCursorChangeClient->receiveCursorInfo(name, tex, size_x, size_y, hotspot_x, hotspot_y); + } + } +} + void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e2a966660..bbcdbbb41 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -48,6 +48,11 @@ namespace OEngine } } +namespace SFO +{ + class CursorChangeClient; +} + namespace MWGui { class WindowBase; @@ -228,6 +233,8 @@ namespace MWGui virtual const Translation::Storage& getTranslationDataStorage() const; + virtual void setCursorChangeClient(SFO::CursorChangeClient* client); + private: OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; @@ -282,6 +289,8 @@ namespace MWGui MyGUI::Gui *mGui; // Gui std::vector mGuiModes; + SFO::CursorChangeClient* mCursorChangeClient; + std::vector mGarbageDialogs; void cleanupGarbage(); @@ -310,6 +319,8 @@ namespace MWGui * so this method will retrieve the GMST with the name \a _tag and place the result in \a _result */ void onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result); + + void onCursorChange(const std::string& name); }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7785167f8..c1f857b5f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -67,6 +67,8 @@ namespace MWInput mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); + mWindows.setCursorChangeClient(mInputManager); + std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index e194719cb..1b996ce06 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX # include @@ -13,6 +15,8 @@ namespace SFO { + /// \brief General purpose wrapper for OGRE applications around SDL's event + /// queue, mostly used for handling input-related events. InputWrapper::InputWrapper(Ogre::RenderWindow *window) : mWindow(window), mSDLWindow(NULL), @@ -58,6 +62,11 @@ namespace SFO if(mSDLWindow == NULL) return false; + //without this SDL will take ownership of the window and iconify it when + //we alt-tab away. + SDL_SetWindowFullscreen(mSDLWindow, 0); + + //translate our keypresses into text SDL_StartTextInput(); #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX @@ -160,6 +169,7 @@ namespace SFO return SDL_GetModState() & mod; } + /// \brief Moves the mouse to the specified point within the viewport void InputWrapper::warpMouse(int x, int y) { SDL_WarpMouseInWindow(mSDLWindow, x, y); @@ -168,14 +178,15 @@ namespace SFO mWarpY = y; } + /// \brief Locks the pointer to the window void InputWrapper::setGrabPointer(bool grab) { - SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; - mGrabPointer = grab; - SDL_SetWindowGrab(mSDLWindow, sdlGrab); + SDL_SetWindowGrab(mSDLWindow, grab ? SDL_TRUE : SDL_FALSE); } + /// \brief Set the mouse to relative positioning. Doesn't move the cursor + /// and disables mouse acceleration. void InputWrapper::setMouseRelative(bool relative) { if(mMouseRelative == relative) @@ -200,6 +211,121 @@ namespace SFO SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); } + bool InputWrapper::cursorChanged(const std::string &name) + { + CursorMap::const_iterator curs_iter = mCursorMap.find(name); + + //we have this cursor + if(curs_iter != mCursorMap.end()) + { + SDL_SetCursor(curs_iter->second); + return false; + } + else + { + //they should get back to use with more info + return true; + } + } + + void InputWrapper::receiveCursorInfo(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + _createCursorFromResource(name, tex, size_x, size_y, hotspot_x, hotspot_y); + } + + /// \brief creates an SDL cursor from an Ogre texture + void InputWrapper::_createCursorFromResource(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + Ogre::Image::Box box; + box.right = size_x; + box.bottom = size_y; + + //get the surfaces set up + Ogre::HardwarePixelBufferSharedPtr buffer = tex.get()->getBuffer(); + buffer.get()->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY); + + std::string tempName = "_" + name + "_processing"; + + //we need to copy this to a temporary texture since Ogre doesn't like us using getColourAt + Ogre::TexturePtr tempTexture = Ogre::TextureManager::getSingleton().createManual( + tempName, + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + size_x, size_y, + 0, + Ogre::PF_FLOAT16_RGBA, + Ogre::TU_STATIC); + + tempTexture->getBuffer()->blit(buffer); + buffer->unlock(); + + Ogre::HardwarePixelBufferSharedPtr new_buffer = tempTexture.get()->getBuffer(); + //FIXME: Casting away constness is almost certainly the wrong thing to do here + Ogre::PixelBox& pixels = const_cast(new_buffer->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY)); + + + SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0,0,0,0); + + + //copy the Ogre texture to an SDL surface + for(size_t x = 0; x < size_x; ++x) + { + for(size_t y = 0; y < size_y; ++y) + { + Ogre::ColourValue clr = pixels.getColourAt(x, y, 0); + + //set the pixel on the SDL surface to the same value as the Ogre texture's + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r, clr.g, clr.b, clr.a)); + } + } + + //set the cursor and store it for later + SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); + SDL_SetCursor(curs); + mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); + + new_buffer->unlock(); + + //clean up + SDL_FreeSurface(surf); + Ogre::TextureManager::getSingleton().remove(tempName); + } + + void InputWrapper::_putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) + { + int bpp = surface->format->BytesPerPixel; + /* Here p is the address to the pixel we want to set */ + Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; + + switch(bpp) { + case 1: + *p = pixel; + break; + + case 2: + *(Uint16 *)p = pixel; + break; + + case 3: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (pixel >> 16) & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = pixel & 0xff; + } else { + p[0] = pixel & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = (pixel >> 16) & 0xff; + } + break; + + case 4: + *(Uint32 *)p = pixel; + break; + } + } + + /// \brief Internal method for ignoring relative motions as a side effect + /// of warpMouse() bool InputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) { if(!mWarpCompensate) @@ -215,6 +341,7 @@ namespace SFO return false; } + /// \brief Wrap the mouse to the viewport void InputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) { //don't wrap if we don't want relative movements, support relative @@ -238,6 +365,7 @@ namespace SFO } } + /// \brief Package mouse and mousewheel motions into a single event MouseMotionEvent InputWrapper::_packageMouseMotion(const SDL_Event &evt) { MouseMotionEvent pack_evt; diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index eba2ed8d0..aac2bf566 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -9,13 +9,33 @@ #include "events.h" +namespace Ogre +{ + class Texture; +} + namespace SFO { - class InputWrapper + + + class CursorChangeClient + { + public: + /// \brief Tell the client that the cursor has changed, giving the + /// name of the cursor we changed to ("arrow", "ibeam", etc) + /// \return Whether the client is interested in more information about the cursor + virtual bool cursorChanged(const std::string &name) = 0; + + /// \brief Follow up a cursorChanged() call with enough info to create an SDL cursor. + virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; + }; + + class InputWrapper : + public CursorChangeClient { public: InputWrapper(Ogre::RenderWindow* window); - ~InputWrapper(); + virtual ~InputWrapper(); void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } @@ -28,9 +48,13 @@ namespace SFO bool getMouseRelative() { return mMouseRelative; } void setGrabPointer(bool grab); + virtual bool cursorChanged(const std::string &name); + virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code); void warpMouse(int x, int y); + private: bool _start(); @@ -38,6 +62,9 @@ namespace SFO void _wrapMousePointer(const SDL_MouseMotionEvent &evt); MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); + void _createCursorFromResource(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); + void _handleKeyPress(SDL_KeyboardEvent& evt); Uint32 _UTF8ToUTF32(const unsigned char *buf); void _setupOISKeys(); @@ -49,6 +76,9 @@ namespace SFO typedef boost::unordered_map KeyMap; KeyMap mKeyMap; + typedef std::map CursorMap; + CursorMap mCursorMap; + Uint16 mWarpX; Uint16 mWarpY; bool mWarpCompensate; @@ -63,6 +93,7 @@ namespace SFO Ogre::RenderWindow* mWindow; SDL_Window* mSDLWindow; }; + } #endif From eeacb04fe24e4d21f91c407e839c662a8f41a83d Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 11 Jan 2013 09:32:29 -0400 Subject: [PATCH 015/817] Fully working hardware cursors (if you compile SDL2 with XCursor support) --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 22 ++++++++++++++++------ apps/openmw/mwgui/windowmanagerimp.hpp | 3 ++- extern/sdl4ogre/sdlinputwrapper.cpp | 9 +++++++-- extern/sdl4ogre/sdlinputwrapper.hpp | 4 ++++ 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index e7a63a1b5..c7dc06472 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -159,7 +159,7 @@ namespace MWBase virtual void setFocusObject(const MWWorld::Ptr& focus) = 0; virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0; - virtual void setMouseVisible(bool visible) = 0; + virtual void setCursorVisible(bool visible) = 0; virtual void getMousePosition(int &x, int &y) = 0; virtual void getMousePosition(float &x, float &y) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7c99d004e..781f3c86c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -190,6 +190,9 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + //make sure the cursor in the GL context isn't visible + MyGUI::PointerManager::getInstance().setVisible(false); + // The HUD is always on mHud->setVisible(true); @@ -302,7 +305,7 @@ void WindowManager::updateVisible() mHud->setVisible(true); // Mouse is visible whenever we're not in game mode - MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); + setCursorVisible(isGuiMode()); bool gameMode = !isGuiMode(); @@ -417,13 +420,13 @@ void WindowManager::updateVisible() break; case GM_LoadingWallpaper: mHud->setVisible(false); - MyGUI::PointerManager::getInstance().setVisible(false); + setCursorVisible(false); break; case GM_Loading: - MyGUI::PointerManager::getInstance().setVisible(false); + setCursorVisible(false); break; case GM_Video: - MyGUI::PointerManager::getInstance().setVisible(false); + setCursorVisible(false); mHud->setVisible(false); break; default: @@ -737,9 +740,15 @@ void WindowManager::setSpellVisibility(bool visible) mHud->setEffectVisible (visible); } -void WindowManager::setMouseVisible(bool visible) +void WindowManager::setCursorVisible(bool visible) { - MyGUI::PointerManager::getInstance().setVisible(visible); + if(visible == mCursorVisible) + return; + + mCursorVisible = visible; + + if(mCursorChangeClient != NULL) + mCursorChangeClient->cursorVisible(visible); } void WindowManager::setDragDrop(bool dragDrop) @@ -775,6 +784,7 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r { mCursorChangeClient = client; onCursorChange(PointerManager::getInstance().getDefaultPointer()); + client->cursorVisible(mCursorVisible); } void WindowManager::onCursorChange(const std::string &name) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index bbcdbbb41..4334de83f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -154,7 +154,7 @@ namespace MWGui virtual void setFocusObject(const MWWorld::Ptr& focus); virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); - virtual void setMouseVisible(bool visible); + virtual void setCursorVisible(bool visible); virtual void getMousePosition(int &x, int &y); virtual void getMousePosition(float &x, float &y); virtual void setDragDrop(bool dragDrop); @@ -275,6 +275,7 @@ namespace MWGui bool mCrosshairEnabled; bool mSubtitlesEnabled; bool mHudEnabled; + bool mCursorVisible; /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. // Various stats about player as needed by window manager diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 1b996ce06..c996924e4 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -228,6 +228,11 @@ namespace SFO } } + void InputWrapper::cursorVisible(bool visible) + { + SDL_ShowCursor(visible ? SDL_TRUE : SDL_FALSE); + } + void InputWrapper::receiveCursorInfo(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { _createCursorFromResource(name, tex, size_x, size_y, hotspot_x, hotspot_y); @@ -264,7 +269,7 @@ namespace SFO Ogre::PixelBox& pixels = const_cast(new_buffer->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY)); - SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0,0,0,0); + SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); //copy the Ogre texture to an SDL surface @@ -275,7 +280,7 @@ namespace SFO Ogre::ColourValue clr = pixels.getColourAt(x, y, 0); //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r, clr.g, clr.b, clr.a)); + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); } } diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index aac2bf566..d37a43e33 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -28,6 +28,9 @@ namespace SFO /// \brief Follow up a cursorChanged() call with enough info to create an SDL cursor. virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; + + /// \brief Tell the client when the cursor visibility changed + virtual void cursorVisible(bool visible) = 0; }; class InputWrapper : @@ -50,6 +53,7 @@ namespace SFO virtual bool cursorChanged(const std::string &name); virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + virtual void cursorVisible(bool visible); OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code); From 651a654985a50820bed817f4374cbbc83a842afa Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 11 Jan 2013 10:09:26 -0400 Subject: [PATCH 016/817] clean up our cursors during destruction --- extern/sdl4ogre/sdlinputwrapper.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index c996924e4..190612fd8 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -37,6 +37,17 @@ namespace SFO if(mSDLWindow != NULL) SDL_DestroyWindow(mSDLWindow); mSDLWindow = NULL; + + CursorMap::const_iterator curs_iter = mCursorMap.begin(); + + while(curs_iter != mCursorMap.end()) + { + SDL_FreeCursor(curs_iter->second); + ++curs_iter; + } + + mCursorMap.clear(); + SDL_StopTextInput(); SDL_Quit(); } From d71b58385536589e58b16bb8d2f8d3c1cac6a9cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jan 2013 22:25:34 +0100 Subject: [PATCH 017/817] fix const cast, fix comment --- extern/sdl4ogre/sdlinputwrapper.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 190612fd8..b6761e883 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -252,17 +252,14 @@ namespace SFO /// \brief creates an SDL cursor from an Ogre texture void InputWrapper::_createCursorFromResource(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { - Ogre::Image::Box box; - box.right = size_x; - box.bottom = size_y; - //get the surfaces set up Ogre::HardwarePixelBufferSharedPtr buffer = tex.get()->getBuffer(); - buffer.get()->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY); + buffer.get()->lock(Ogre::HardwarePixelBuffer::HBL_READ_ONLY); std::string tempName = "_" + name + "_processing"; - //we need to copy this to a temporary texture since Ogre doesn't like us using getColourAt + //we need to copy this to a temporary texture first because the cursors might be in DDS format, + //and Ogre doesn't have an interface to read DDS Ogre::TexturePtr tempTexture = Ogre::TextureManager::getSingleton().createManual( tempName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, @@ -275,10 +272,9 @@ namespace SFO tempTexture->getBuffer()->blit(buffer); buffer->unlock(); - Ogre::HardwarePixelBufferSharedPtr new_buffer = tempTexture.get()->getBuffer(); - //FIXME: Casting away constness is almost certainly the wrong thing to do here - Ogre::PixelBox& pixels = const_cast(new_buffer->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY)); - + // now blit to memory + Ogre::Image destImage; + tempTexture->convertToImage(destImage); SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); @@ -288,7 +284,7 @@ namespace SFO { for(size_t y = 0; y < size_y; ++y) { - Ogre::ColourValue clr = pixels.getColourAt(x, y, 0); + Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); //set the pixel on the SDL surface to the same value as the Ogre texture's _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); @@ -300,8 +296,6 @@ namespace SFO SDL_SetCursor(curs); mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); - new_buffer->unlock(); - //clean up SDL_FreeSurface(surf); Ogre::TextureManager::getSingleton().remove(tempName); From 5a6589af0155b058fc63c095f38c8568c59f6c77 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 12 Jan 2013 11:57:29 -0400 Subject: [PATCH 018/817] extract cursor management to a separate class, have windowmanager communicate with it. Initialize SDL during engine start --- apps/openmw/engine.cpp | 15 ++ apps/openmw/mwbase/windowmanager.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 57 +++--- apps/openmw/mwgui/windowmanagerimp.hpp | 9 +- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +- extern/sdl4ogre/CMakeLists.txt | 8 +- extern/sdl4ogre/cursormanager.hpp | 35 ++++ extern/sdl4ogre/sdlcursormanager.cpp | 189 ++++++++++++++++++++ extern/sdl4ogre/sdlcursormanager.hpp | 44 +++++ extern/sdl4ogre/sdlinputwrapper.cpp | 220 +++++------------------- extern/sdl4ogre/sdlinputwrapper.hpp | 41 +---- 11 files changed, 382 insertions(+), 249 deletions(-) create mode 100644 extern/sdl4ogre/cursormanager.hpp create mode 100644 extern/sdl4ogre/sdlcursormanager.cpp create mode 100644 extern/sdl4ogre/sdlcursormanager.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4413e98f4..51dbabba5 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -36,6 +36,8 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" +#include "SDL2/SDL.h" + void OMW::Engine::executeLocalScripts() { @@ -272,6 +274,9 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); + settings.setBool("hardware cursors", "GUI", true); + settings.setBool("debug", "Engine", mDebug); + return settingspath; } @@ -322,6 +327,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) loadBSA(); + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + if(SDL_WasInit(flags) == 0) + { + //kindly ask SDL not to trash our OGL context + //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + if(SDL_Init(flags) != 0) + throw std::runtime_error("Couldn't initialize SDL!"); + } + // cursor replacer (converts the cursor from the bsa so they can be used by mygui) MWGui::CursorReplace replacer; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c7dc06472..06b1df7b9 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -57,7 +57,7 @@ namespace MWGui namespace SFO { - class CursorChangeClient; + class CursorManager; } namespace MWBase @@ -243,8 +243,6 @@ namespace MWBase virtual void startTraining(MWWorld::Ptr actor) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; - - virtual void setCursorChangeClient(SFO::CursorChangeClient* client) = 0; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 781f3c86c..20301b1b2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include @@ -115,7 +115,8 @@ WindowManager::WindowManager( , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHudEnabled(true) , mTranslationDataStorage (translationDataStorage) - , mCursorChangeClient(NULL) + , mCursorManager(NULL) + , mUseHardwareCursors(Settings::Manager::getBool("hardware cursors", "GUI")) { // Set up the GUI system @@ -190,9 +191,6 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); - //make sure the cursor in the GL context isn't visible - MyGUI::PointerManager::getInstance().setVisible(false); - // The HUD is always on mHud->setVisible(true); @@ -212,6 +210,13 @@ WindowManager::WindowManager( unsetSelectedSpell(); unsetSelectedWeapon(); + //set up the hardware cursor manager + mCursorManager = new SFO::SDLCursorManager(Settings::Manager::getBool("debug", "Engine")); + + setUseHardwareCursors(mUseHardwareCursors); + onCursorChange(PointerManager::getInstance().getDefaultPointer()); + mCursorManager->cursorVisibilityChange(false); + // Set up visibility updateVisible(); } @@ -252,6 +257,7 @@ WindowManager::~WindowManager() cleanupGarbage(); delete mGuiManager; + delete mCursorManager; } void WindowManager::cleanupGarbage() @@ -740,15 +746,30 @@ void WindowManager::setSpellVisibility(bool visible) mHud->setEffectVisible (visible); } +void WindowManager::setUseHardwareCursors(bool use) +{ + mCursorManager->setEnabled(use); + + if(!use) + { + MyGUI::PointerManager::getInstance().setVisible(false); + } + else + { + MyGUI::PointerManager::getInstance().setVisible(mCursorVisible); + } +} + void WindowManager::setCursorVisible(bool visible) { - if(visible == mCursorVisible) + if(mCursorVisible == visible) return; mCursorVisible = visible; + mCursorManager->cursorVisibilityChange(visible); - if(mCursorChangeClient != NULL) - mCursorChangeClient->cursorVisible(visible); + if(!mUseHardwareCursors) + MyGUI::PointerManager::getInstance().setVisible(visible); } void WindowManager::setDragDrop(bool dragDrop) @@ -780,21 +801,10 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r } } - void WindowManager::setCursorChangeClient(SFO::CursorChangeClient* client) - { - mCursorChangeClient = client; - onCursorChange(PointerManager::getInstance().getDefaultPointer()); - client->cursorVisible(mCursorVisible); - } - void WindowManager::onCursorChange(const std::string &name) { - //we have no client, don't care. - if(!mCursorChangeClient) - return; - - //the client doesn't want any more info about this cursor - if(!mCursorChangeClient->cursorChanged(name)) + //the cursor manager doesn't want any more info about this cursor + if(!mCursorManager->cursorChanged(name)) return; //See if we can get the information we need out of the cursor resource ResourceImageSetPointerFix* imgSetPtr = dynamic_cast(MyGUI::PointerManager::getInstance().getByName(name)); @@ -806,7 +816,7 @@ void WindowManager::onCursorChange(const std::string &name) Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName(tex_name); - //everything looks good, send it to the client + //everything looks good, send it to the cursor manager if(!tex.isNull()) { Uint8 size_x = imgSetPtr->getSize().width; @@ -814,7 +824,7 @@ void WindowManager::onCursorChange(const std::string &name) Uint8 hotspot_x = imgSetPtr->getHotSpot().left; Uint8 hotspot_y = imgSetPtr->getHotSpot().top; - mCursorChangeClient->receiveCursorInfo(name, tex, size_x, size_y, hotspot_x, hotspot_y); + mCursorManager->receiveCursorInfo(name, tex, size_x, size_y, hotspot_x, hotspot_y); } } } @@ -823,6 +833,7 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector { mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); + setUseHardwareCursors(Settings::Manager::getBool("hardware cursors", "GUI")); bool changeRes = false; for (Settings::CategorySettingVector::const_iterator it = changed.begin(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 4334de83f..874de8af9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -50,7 +50,7 @@ namespace OEngine namespace SFO { - class CursorChangeClient; + class CursorManager; } namespace MWGui @@ -233,8 +233,6 @@ namespace MWGui virtual const Translation::Storage& getTranslationDataStorage() const; - virtual void setCursorChangeClient(SFO::CursorChangeClient* client); - private: OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; @@ -290,7 +288,7 @@ namespace MWGui MyGUI::Gui *mGui; // Gui std::vector mGuiModes; - SFO::CursorChangeClient* mCursorChangeClient; + SFO::CursorManager* mCursorManager; std::vector mGarbageDialogs; void cleanupGarbage(); @@ -315,6 +313,9 @@ namespace MWGui void onDialogueWindowBye(); + bool mUseHardwareCursors; + void setUseHardwareCursors(bool use); + /** * Called when MyGUI tries to retrieve a tag. This usually corresponds to a GMST string, * so this method will retrieve the GMST with the name \a _tag and place the result in \a _result diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c1f857b5f..9d80de91e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -67,8 +68,6 @@ namespace MWInput mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); - mWindows.setCursorChangeClient(mInputManager); - std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -225,6 +224,9 @@ namespace MWInput bool was_relative = mInputManager->getMouseRelative(); bool is_relative = !mWindows.isGuiMode(); + //we let the mouse escape in the main menu + mInputManager->setGrabPointer(!main_menu); + // don't keep the pointer away from the window edge in gui mode // stop using raw mouse motions and switch to system cursor movements mInputManager->setMouseRelative(is_relative); @@ -235,9 +237,6 @@ namespace MWInput { mInputManager->warpMouse(mMouseX, mMouseY); } - - //we let the mouse escape in the main menu - mInputManager->setGrabPointer(!main_menu); } // Disable movement in Gui mode diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt index c52dd4cb4..493d1ce47 100644 --- a/extern/sdl4ogre/CMakeLists.txt +++ b/extern/sdl4ogre/CMakeLists.txt @@ -4,9 +4,15 @@ set(SDL4OGRE_LIBRARY "sdl4ogre") set(SDL4OGRE_SOURCE_FILES sdlinputwrapper.cpp + sdlcursormanager.cpp ) -add_library(${SDL4OGRE_LIBRARY} STATIC ${SDL4OGRE_SOURCE_FILES}) +set(SDL4OGRE_HEADER_FILES + OISCompat.h + cursormanager.hpp +) + +add_library(${SDL4OGRE_LIBRARY} STATIC ${SDL4OGRE_SOURCE_FILES} ${SDL4OGRE_HEADER_FILES}) link_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/extern/sdl4ogre/cursormanager.hpp b/extern/sdl4ogre/cursormanager.hpp new file mode 100644 index 000000000..938f5f4c2 --- /dev/null +++ b/extern/sdl4ogre/cursormanager.hpp @@ -0,0 +1,35 @@ +#ifndef _SDL4OGRE_CURSOR_MANAGER_H +#define _SDL4OGRE_CURSOR_MANAGER_H + +#include "SDL2/SDL_types.h" +#include + +namespace Ogre +{ + class TexturePtr; +} + +namespace SFO +{ +class CursorManager +{ +public: + virtual ~CursorManager(){} + + /// \brief Tell the manager that the cursor has changed, giving the + /// name of the cursor we changed to ("arrow", "ibeam", etc) + /// \return Whether the manager is interested in more information about the cursor + virtual bool cursorChanged(const std::string &name) = 0; + + /// \brief Follow up a cursorChanged() call with enough info to create an cursor. + virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; + + /// \brief Tell the manager when the cursor visibility changed + virtual void cursorVisibilityChange(bool visible) = 0; + + /// \brief sets whether to actively manage cursors or not + virtual void setEnabled(bool enabled) = 0; +}; +} + +#endif diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp new file mode 100644 index 000000000..4e24696ea --- /dev/null +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -0,0 +1,189 @@ +#include "sdlcursormanager.hpp" + +#include +#include + +namespace SFO +{ + + SDLCursorManager::SDLCursorManager(bool debug) : + mDebug(debug), + mEnabled(false), + mCursorVisible(false), + mInitialized(false) + { + } + + SDLCursorManager::~SDLCursorManager() + { + CursorMap::const_iterator curs_iter = mCursorMap.begin(); + + while(curs_iter != mCursorMap.end()) + { + SDL_FreeCursor(curs_iter->second); + ++curs_iter; + } + + mCursorMap.clear(); + } + + void SDLCursorManager::setEnabled(bool enabled) + { + if(mInitialized && enabled == mEnabled) + return; + + mInitialized = true; + mEnabled = enabled; + + //turn on hardware cursors + if(enabled) + { + _setGUICursor(mCurrentCursor); + } + //turn off hardware cursors + else + { + if(!mDebug) + SDL_ShowCursor(SDL_FALSE); + } + } + + bool SDLCursorManager::cursorChanged(const std::string &name) + { + mCurrentCursor = name; + + CursorMap::const_iterator curs_iter = mCursorMap.find(name); + + //we have this cursor + if(curs_iter != mCursorMap.end()) + { + _setGUICursor(name); + + return false; + } + else + { + //they should get back to us with more info + return true; + } + } + + void SDLCursorManager::_setGUICursor(const std::string &name) + { + if(mEnabled && (mDebug || mCursorVisible)) + { + SDL_SetCursor(mCursorMap.find(name)->second); + _setCursorVisible(mCursorVisible); + } + } + + void SDLCursorManager::_setCursorVisible(bool visible) + { + if(!mEnabled) + return; + + if(mDebug) + visible = true; + + SDL_ShowCursor(visible ? SDL_TRUE : SDL_FALSE); + } + + void SDLCursorManager::cursorVisibilityChange(bool visible) + { + mCursorVisible = visible; + + _setGUICursor(mCurrentCursor); + _setCursorVisible(visible); + } + + void SDLCursorManager::receiveCursorInfo(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + _createCursorFromResource(name, tex, size_x, size_y, hotspot_x, hotspot_y); + } + + /// \brief creates an SDL cursor from an Ogre texture + void SDLCursorManager::_createCursorFromResource(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + //get the surfaces set up + Ogre::HardwarePixelBufferSharedPtr buffer = tex.get()->getBuffer(); + buffer.get()->lock(Ogre::HardwarePixelBuffer::HBL_READ_ONLY); + + std::string tempName = "_" + name + "_processing"; + + //we need to copy this to a temporary texture first because the cursors might be in DDS format, + //and Ogre doesn't have an interface to read DDS + Ogre::TexturePtr tempTexture = Ogre::TextureManager::getSingleton().createManual( + tempName, + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + size_x, size_y, + 0, + Ogre::PF_FLOAT16_RGBA, + Ogre::TU_STATIC); + + tempTexture->getBuffer()->blit(buffer); + buffer->unlock(); + + // now blit to memory + Ogre::Image destImage; + tempTexture->convertToImage(destImage); + + SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); + + + //copy the Ogre texture to an SDL surface + for(size_t x = 0; x < size_x; ++x) + { + for(size_t y = 0; y < size_y; ++y) + { + Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); + + //set the pixel on the SDL surface to the same value as the Ogre texture's + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); + } + } + + //set the cursor and store it for later + SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); + mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); + + //clean up + SDL_FreeSurface(surf); + Ogre::TextureManager::getSingleton().remove(tempName); + + _setGUICursor(name); + } + + void SDLCursorManager::_putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) + { + int bpp = surface->format->BytesPerPixel; + /* Here p is the address to the pixel we want to set */ + Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; + + switch(bpp) { + case 1: + *p = pixel; + break; + + case 2: + *(Uint16 *)p = pixel; + break; + + case 3: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (pixel >> 16) & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = pixel & 0xff; + } else { + p[0] = pixel & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = (pixel >> 16) & 0xff; + } + break; + + case 4: + *(Uint32 *)p = pixel; + break; + } + } +} diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp new file mode 100644 index 000000000..2de192377 --- /dev/null +++ b/extern/sdl4ogre/sdlcursormanager.hpp @@ -0,0 +1,44 @@ +#ifndef _SDL4OGRE_CURSORMANAGER_H +#define _SDL4OGRE_CURSORMANAGER_H + +#include "SDL.h" + +#include "cursormanager.hpp" +#include + +namespace SFO +{ + class SDLCursorManager : + public CursorManager + { + public: + SDLCursorManager(bool debug=false); + virtual ~SDLCursorManager(); + + virtual void setEnabled(bool enabled); + + virtual bool cursorChanged(const std::string &name); + virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + virtual void cursorVisibilityChange(bool visible); + + private: + void _createCursorFromResource(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); + + void _setGUICursor(const std::string& name); + void _setCursorVisible(bool visible); + + typedef std::map CursorMap; + CursorMap mCursorMap; + + SDL_Cursor* mDebugCursor; + std::string mCurrentCursor; + bool mEnabled; + bool mInitialized; + bool mCursorVisible; + bool mDebug; + + }; +} + +#endif diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index b6761e883..529740d5e 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX @@ -28,8 +27,8 @@ namespace SFO mMouseY(0), mMouseX(0) { - _start(); _setupOISKeys(); + _start(); } InputWrapper::~InputWrapper() @@ -38,82 +37,60 @@ namespace SFO SDL_DestroyWindow(mSDLWindow); mSDLWindow = NULL; - CursorMap::const_iterator curs_iter = mCursorMap.begin(); - - while(curs_iter != mCursorMap.end()) - { - SDL_FreeCursor(curs_iter->second); - ++curs_iter; - } - - mCursorMap.clear(); - SDL_StopTextInput(); SDL_Quit(); } bool InputWrapper::_start() { - Uint32 flags = SDL_INIT_VIDEO; - if(SDL_WasInit(flags) == 0) - { - //get the HWND from ogre's renderwindow - size_t windowHnd; - mWindow->getCustomAttribute("WINDOW", &windowHnd); + //get the HWND from ogre's renderwindow + size_t windowHnd; + mWindow->getCustomAttribute("WINDOW", &windowHnd); - //kindly ask SDL not to trash our OGL context - //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - if(SDL_Init(SDL_INIT_VIDEO) != 0) - return false; + //wrap our own event handler around ogre's + mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); - //wrap our own event handler around ogre's - mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + if(mSDLWindow == NULL) + return false; - if(mSDLWindow == NULL) - return false; + //without this SDL will take ownership of the window and iconify it when + //we alt-tab away. + SDL_SetWindowFullscreen(mSDLWindow, 0); - //without this SDL will take ownership of the window and iconify it when - //we alt-tab away. - SDL_SetWindowFullscreen(mSDLWindow, 0); - - //translate our keypresses into text - SDL_StartTextInput(); + //translate our keypresses into text + SDL_StartTextInput(); #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - //linux-specific event-handling fixups - //see http://bugzilla.libsdl.org/show_bug.cgi?id=730 - SDL_SysWMinfo wm_info; - SDL_VERSION(&wm_info.version); + //linux-specific event-handling fixups + //see http://bugzilla.libsdl.org/show_bug.cgi?id=730 + SDL_SysWMinfo wm_info; + SDL_VERSION(&wm_info.version); - if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) - { - Display* display = wm_info.info.x11.display; - Window w = wm_info.info.x11.window; + if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) + { + Display* display = wm_info.info.x11.display; + Window w = wm_info.info.x11.window; - // Set the input hints so we get keyboard input - XWMHints *wmhints = XAllocWMHints(); - if (wmhints) { - wmhints->input = True; - wmhints->flags = InputHint; - XSetWMHints(display, w, wmhints); - XFree(wmhints); - } - - //make sure to subscribe to XLib's events - XSelectInput(display, w, - (FocusChangeMask | EnterWindowMask | LeaveWindowMask | - ExposureMask | ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | KeyPressMask | KeyReleaseMask | - PropertyChangeMask | StructureNotifyMask | - KeymapStateMask)); - - XFlush(display); + // Set the input hints so we get keyboard input + XWMHints *wmhints = XAllocWMHints(); + if (wmhints) { + wmhints->input = True; + wmhints->flags = InputHint; + XSetWMHints(display, w, wmhints); + XFree(wmhints); } -#endif - SDL_ShowCursor(SDL_FALSE); - } + //make sure to subscribe to XLib's events + XSelectInput(display, w, + (FocusChangeMask | EnterWindowMask | LeaveWindowMask | + ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | KeyPressMask | KeyReleaseMask | + PropertyChangeMask | StructureNotifyMask | + KeymapStateMask)); + + XFlush(display); + } +#endif return true; } @@ -209,10 +186,11 @@ namespace SFO //eep, wrap the pointer manually if the input driver doesn't support //relative positioning natively - if(SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == -1) + SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE); + + if(relative) { - if(relative) - mWrapPointer = true; + mWrapPointer = true; } //now remove all mouse events using the old setting from the queue @@ -222,118 +200,6 @@ namespace SFO SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); } - bool InputWrapper::cursorChanged(const std::string &name) - { - CursorMap::const_iterator curs_iter = mCursorMap.find(name); - - //we have this cursor - if(curs_iter != mCursorMap.end()) - { - SDL_SetCursor(curs_iter->second); - return false; - } - else - { - //they should get back to use with more info - return true; - } - } - - void InputWrapper::cursorVisible(bool visible) - { - SDL_ShowCursor(visible ? SDL_TRUE : SDL_FALSE); - } - - void InputWrapper::receiveCursorInfo(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) - { - _createCursorFromResource(name, tex, size_x, size_y, hotspot_x, hotspot_y); - } - - /// \brief creates an SDL cursor from an Ogre texture - void InputWrapper::_createCursorFromResource(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) - { - //get the surfaces set up - Ogre::HardwarePixelBufferSharedPtr buffer = tex.get()->getBuffer(); - buffer.get()->lock(Ogre::HardwarePixelBuffer::HBL_READ_ONLY); - - std::string tempName = "_" + name + "_processing"; - - //we need to copy this to a temporary texture first because the cursors might be in DDS format, - //and Ogre doesn't have an interface to read DDS - Ogre::TexturePtr tempTexture = Ogre::TextureManager::getSingleton().createManual( - tempName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - size_x, size_y, - 0, - Ogre::PF_FLOAT16_RGBA, - Ogre::TU_STATIC); - - tempTexture->getBuffer()->blit(buffer); - buffer->unlock(); - - // now blit to memory - Ogre::Image destImage; - tempTexture->convertToImage(destImage); - - SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); - - - //copy the Ogre texture to an SDL surface - for(size_t x = 0; x < size_x; ++x) - { - for(size_t y = 0; y < size_y; ++y) - { - Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); - - //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); - } - } - - //set the cursor and store it for later - SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); - SDL_SetCursor(curs); - mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); - - //clean up - SDL_FreeSurface(surf); - Ogre::TextureManager::getSingleton().remove(tempName); - } - - void InputWrapper::_putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) - { - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to set */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - - switch(bpp) { - case 1: - *p = pixel; - break; - - case 2: - *(Uint16 *)p = pixel; - break; - - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { - p[0] = (pixel >> 16) & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = pixel & 0xff; - } else { - p[0] = pixel & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = (pixel >> 16) & 0xff; - } - break; - - case 4: - *(Uint32 *)p = pixel; - break; - } - } - /// \brief Internal method for ignoring relative motions as a side effect /// of warpMouse() bool InputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index d37a43e33..5233fee8b 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -1,7 +1,8 @@ -#ifndef _MWINPUT_SDLINPUTWRAPPER_H -#define _MWINPUT_SDLINPUTWRAPPER_H +#ifndef _SDL4OGRE_SDLINPUTWRAPPER_H +#define _SDL4OGRE_SDLINPUTWRAPPER_H #include "SDL2/SDL_events.h" + #include #include @@ -9,36 +10,14 @@ #include "events.h" -namespace Ogre -{ - class Texture; -} namespace SFO { - - - class CursorChangeClient - { - public: - /// \brief Tell the client that the cursor has changed, giving the - /// name of the cursor we changed to ("arrow", "ibeam", etc) - /// \return Whether the client is interested in more information about the cursor - virtual bool cursorChanged(const std::string &name) = 0; - - /// \brief Follow up a cursorChanged() call with enough info to create an SDL cursor. - virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; - - /// \brief Tell the client when the cursor visibility changed - virtual void cursorVisible(bool visible) = 0; - }; - - class InputWrapper : - public CursorChangeClient + class InputWrapper { public: InputWrapper(Ogre::RenderWindow* window); - virtual ~InputWrapper(); + ~InputWrapper(); void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } @@ -51,10 +30,6 @@ namespace SFO bool getMouseRelative() { return mMouseRelative; } void setGrabPointer(bool grab); - virtual bool cursorChanged(const std::string &name); - virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); - virtual void cursorVisible(bool visible); - OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code); void warpMouse(int x, int y); @@ -66,9 +41,6 @@ namespace SFO void _wrapMousePointer(const SDL_MouseMotionEvent &evt); MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); - void _createCursorFromResource(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); - void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); - void _handleKeyPress(SDL_KeyboardEvent& evt); Uint32 _UTF8ToUTF32(const unsigned char *buf); void _setupOISKeys(); @@ -80,9 +52,6 @@ namespace SFO typedef boost::unordered_map KeyMap; KeyMap mKeyMap; - typedef std::map CursorMap; - CursorMap mCursorMap; - Uint16 mWarpX; Uint16 mWarpY; bool mWarpCompensate; From eb08f407d3510ba0e6ccd67feb9f6a4ee5914ab7 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 12 Jan 2013 15:38:22 -0400 Subject: [PATCH 019/817] Oops, remove resource leak in the input wrapper. --- extern/sdl4ogre/sdlinputwrapper.cpp | 33 +++++++++++------------------ extern/sdl4ogre/sdlinputwrapper.hpp | 1 - 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 529740d5e..0a0e321bb 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -28,21 +28,7 @@ namespace SFO mMouseX(0) { _setupOISKeys(); - _start(); - } - InputWrapper::~InputWrapper() - { - if(mSDLWindow != NULL) - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; - - SDL_StopTextInput(); - SDL_Quit(); - } - - bool InputWrapper::_start() - { //get the HWND from ogre's renderwindow size_t windowHnd; mWindow->getCustomAttribute("WINDOW", &windowHnd); @@ -50,12 +36,11 @@ namespace SFO //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); - if(mSDLWindow == NULL) - return false; + assert(mSDLWindow != NULL); //without this SDL will take ownership of the window and iconify it when //we alt-tab away. - SDL_SetWindowFullscreen(mSDLWindow, 0); + //SDL_SetWindowFullscreen(mSDLWindow, 0); //translate our keypresses into text SDL_StartTextInput(); @@ -91,14 +76,20 @@ namespace SFO XFlush(display); } #endif - return true; + } + + InputWrapper::~InputWrapper() + { + if(mSDLWindow != NULL) + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + + SDL_StopTextInput(); + SDL_Quit(); } void InputWrapper::capture() { - if(!_start()) - throw std::runtime_error(SDL_GetError()); - SDL_Event evt; while(SDL_PollEvent(&evt)) { diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 5233fee8b..d3c172b49 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -35,7 +35,6 @@ namespace SFO void warpMouse(int x, int y); private: - bool _start(); bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); void _wrapMousePointer(const SDL_MouseMotionEvent &evt); From b6ec64485c21689375ee7823dc05794bb594c47c Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 12 Jan 2013 17:52:26 -0400 Subject: [PATCH 020/817] fix includes for Windows --- apps/openmw/engine.cpp | 4 +++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- cmake/FindSDL2.cmake | 1 + extern/oics/ICSPrerequisites.h | 10 +++++----- extern/sdl4ogre/OISCompat.h | 4 ++-- extern/sdl4ogre/cursormanager.hpp | 2 +- extern/sdl4ogre/events.h | 2 +- extern/sdl4ogre/sdlcursormanager.hpp | 2 +- extern/sdl4ogre/sdlinputwrapper.cpp | 2 +- extern/sdl4ogre/sdlinputwrapper.hpp | 4 ++-- 10 files changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 51dbabba5..042d10a93 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,4 +1,7 @@ #include "engine.hpp" + +#include + #include "components/esm/loadcell.hpp" #include @@ -36,7 +39,6 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" -#include "SDL2/SDL.h" void OMW::Engine::executeLocalScripts() diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 20301b1b2..e096ee1fb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -4,8 +4,8 @@ #include #include "MyGUI_UString.h" -#include "MYGUI/MyGUI_IPointer.h" -#include "MYGUI/MyGUI_ResourceImageSetPointer.h" +#include "MyGUI_IPointer.h" +#include "MyGUI_ResourceImageSetPointer.h" #include "MyGUI_TextureUtility.h" #include diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 614426ccc..707f5bc3d 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -70,6 +70,7 @@ # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) + FIND_PATH(SDL2_INCLUDE_DIR SDL.h HINTS $ENV{SDL2DIR} diff --git a/extern/oics/ICSPrerequisites.h b/extern/oics/ICSPrerequisites.h index 82c95c86a..2e107355a 100644 --- a/extern/oics/ICSPrerequisites.h +++ b/extern/oics/ICSPrerequisites.h @@ -39,11 +39,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tinyxml.h" -#include "SDL2/SDL_input.h" -#include "SDL2/SDL_keyboard.h" -#include "SDL2/SDL_mouse.h" -#include "SDL2/SDL_joystick.h" -#include "SDL2/SDL_events.h" +#include "SDL_input.h" +#include "SDL_keyboard.h" +#include "SDL_mouse.h" +#include "SDL_joystick.h" +#include "SDL_events.h" /// Define the dll export qualifier if compiling for Windows diff --git a/extern/sdl4ogre/OISCompat.h b/extern/sdl4ogre/OISCompat.h index 04ba2c537..3cffa143d 100644 --- a/extern/sdl4ogre/OISCompat.h +++ b/extern/sdl4ogre/OISCompat.h @@ -1,8 +1,8 @@ #ifndef _OIS_SDL_COMPAT_H #define _OIS_SDL_COMPAT_H -#include -#include +#include +#include namespace OIS { diff --git a/extern/sdl4ogre/cursormanager.hpp b/extern/sdl4ogre/cursormanager.hpp index 938f5f4c2..b98d69ce3 100644 --- a/extern/sdl4ogre/cursormanager.hpp +++ b/extern/sdl4ogre/cursormanager.hpp @@ -1,7 +1,7 @@ #ifndef _SDL4OGRE_CURSOR_MANAGER_H #define _SDL4OGRE_CURSOR_MANAGER_H -#include "SDL2/SDL_types.h" +#include #include namespace Ogre diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 945daf49a..5a0146635 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -1,7 +1,7 @@ #ifndef _SFO_EVENTS_H #define _SFO_EVENTS_H -#include +#include //////////// diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp index 2de192377..ad371f551 100644 --- a/extern/sdl4ogre/sdlcursormanager.hpp +++ b/extern/sdl4ogre/sdlcursormanager.hpp @@ -1,7 +1,7 @@ #ifndef _SDL4OGRE_CURSORMANAGER_H #define _SDL4OGRE_CURSORMANAGER_H -#include "SDL.h" +#include #include "cursormanager.hpp" #include diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 0a0e321bb..da65102e7 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -1,5 +1,5 @@ #include "sdlinputwrapper.hpp" -#include +#include #include #include diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index d3c172b49..9154ff847 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -1,9 +1,9 @@ #ifndef _SDL4OGRE_SDLINPUTWRAPPER_H #define _SDL4OGRE_SDLINPUTWRAPPER_H -#include "SDL2/SDL_events.h" +#include -#include +#include #include #include "OISCompat.h" From 2639bc43839154810a5cacda6d0085e03f0aa9ae Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 12 Jan 2013 18:53:00 -0400 Subject: [PATCH 021/817] Another temp fix for windows --- cmake/FindSDL2.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 707f5bc3d..e0c7feea3 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -166,6 +166,10 @@ IF(SDL2_LIBRARY_TEMP) IF(MINGW) SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) ENDIF(MINGW) + + IF(WIN32) + SET(SDL2_LIBRARY_TEMP winmm imm32 version msimg32 ${SDL2_LIBRARY_TEMP}) + ENDIF(WIN32) # Set the final string here so the GUI reflects the final state. SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") From 043e29c62089159061d74213e055f2c521d68272 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sun, 13 Jan 2013 21:32:45 -0400 Subject: [PATCH 022/817] Have SDL manage the window instead of OGRE to work around SDL Windows bugs (grumble) --- apps/openmw/engine.cpp | 90 ++++++++++++++++++++++++----- apps/openmw/engine.hpp | 2 + extern/sdl4ogre/sdlinputwrapper.cpp | 23 +------- libs/openengine/ogre/renderer.cpp | 64 +++++++++++++++++++- libs/openengine/ogre/renderer.hpp | 7 +++ 5 files changed, 150 insertions(+), 36 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 12a5d4be7..0619281d0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,7 +1,5 @@ #include "engine.hpp" -#include - #include "components/esm/loadcell.hpp" #include @@ -40,6 +38,7 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" +#include void OMW::Engine::executeLocalScripts() { @@ -70,6 +69,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { + handleSDLMessages(); + mEnvironment.setFrameDuration (evt.timeSinceLastFrame); // update input @@ -116,6 +117,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); + + //Flush any events that weren't handled this frame + SDL_FlushEvents(0x0, 0xFFFFFFFF); } catch (const std::exception& e) { @@ -125,6 +129,65 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) return true; } +void OMW::Engine::handleSDLMessages() +{ + //Pump messages since the last frame + const int max_events = 20; + SDL_Event events[max_events]; + + SDL_PumpEvents(); + int num_events = SDL_PeepEvents(events, max_events, SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT); + + bool move_or_resize = false; + + unsigned int size_x = 0; + unsigned int size_y = 0; + + if(num_events != 0) + { + for(int i=0; i < num_events; ++i) + { + switch(events[i].window.event) + { + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_MOVED: + printf("Resizing window!\n"); + move_or_resize = true; + size_x = events[i].window.data1; + size_y = events[i].window.data2; + break; + } + } + } + + //handle window movements + if(move_or_resize) + { + mOgre->adjustViewport(); + if(!mOgre->getWindow()->isFullScreen()) + { + SDL_DisplayMode dispMode; + SDL_Window* sdlWindow = mOgre->getSDLWindow(); + + SDL_GetWindowDisplayMode(sdlWindow, &dispMode); + + dispMode.w = size_x; + dispMode.h = size_y; + + SDL_SetWindowDisplayMode(sdlWindow, &dispMode); + + mOgre->getWindow()->windowMovedOrResized(); + mOgre->getWindow()->resize(size_x, size_y); + } + } + + if(SDL_PeepEvents(NULL, 1, SDL_PEEKEVENT, SDL_QUIT, SDL_QUIT) != 0) + { + //user requested a quit, break out. + mOgre->getRoot()->queueEndRendering(); + } +} + OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) , mFpsLevel(0) @@ -140,6 +203,16 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) { std::srand ( std::time(NULL) ); MWClass::registerClasses(); + + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + if(SDL_WasInit(flags) == 0) + { + //kindly ask SDL not to trash our OGL context + //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + if(SDL_Init(flags) != 0) + throw std::runtime_error("Couldn't initialize SDL!"); + } } OMW::Engine::~Engine() @@ -147,6 +220,7 @@ OMW::Engine::~Engine() mEnvironment.cleanup(); delete mScriptContext; delete mOgre; + SDL_Quit(); } // Load all BSA files in data directory. @@ -317,7 +391,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "shadows"); addZipResource(mResDir / "mygui" / "Obliviontt.zip"); - // Create the window OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); windowSettings.window_x = settings.getInt("resolution x", "Video"); @@ -325,20 +398,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) windowSettings.vsync = settings.getBool("vsync", "Video"); std::string aa = settings.getString("antialiasing", "Video"); windowSettings.fsaa = (aa.substr(0, 4) == "MSAA") ? aa.substr(5, aa.size()-5) : "0"; + mOgre->createWindow("OpenMW", windowSettings); loadBSA(); - Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; - if(SDL_WasInit(flags) == 0) - { - //kindly ask SDL not to trash our OGL context - //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - if(SDL_Init(flags) != 0) - throw std::runtime_error("Couldn't initialize SDL!"); - } - // cursor replacer (converts the cursor from the bsa so they can be used by mygui) MWGui::CursorReplace replacer; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e320c6991..971445147 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -103,6 +103,8 @@ namespace OMW void executeLocalScripts(); + void handleSDLMessages(); + virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); /// Load settings from various files, returns the path to the user settings file diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index da65102e7..cf864b20f 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -85,7 +85,6 @@ namespace SFO mSDLWindow = NULL; SDL_StopTextInput(); - SDL_Quit(); } void InputWrapper::capture() @@ -121,24 +120,6 @@ namespace SFO case SDL_KEYUP: mKeyboardListener->keyReleased(evt.key); break; - - case SDL_WINDOWEVENT_FOCUS_GAINED: - mWindowListener->windowFocusChange(true); - break; - case SDL_WINDOWEVENT_FOCUS_LOST: - mWindowListener->windowFocusChange(false); - break; - case SDL_WINDOWEVENT_EXPOSED: - mWindowListener->windowVisibilityChange(true); - break; - case SDL_WINDOWEVENT_HIDDEN: - mWindowListener->windowVisibilityChange(false); - break; - - //SDL traps ^C signals, pass it to OGRE. - case SDL_QUIT: - Ogre::Root::getSingleton().queueEndRendering(); - break; } } } @@ -186,9 +167,7 @@ namespace SFO //now remove all mouse events using the old setting from the queue SDL_PumpEvents(); - - SDL_Event dummy[20]; - SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); + SDL_FlushEvent(SDL_MOUSEMOTION); } /// \brief Internal method for ignoring relative motions as a side effect diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 3cdb00518..7696095eb 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -1,6 +1,9 @@ #include "renderer.hpp" #include "fader.hpp" +#include +#include + #include "OgreRoot.h" #include "OgreRenderWindow.h" #include "OgreLogManager.h" @@ -47,11 +50,16 @@ void OgreRenderer::cleanup() delete mRoot; mRoot = NULL; + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + unloadPlugins(); } void OgreRenderer::start() { + //TODO: Check if we still need to do this if we're using SDL's + //message pump #if defined(__APPLE__) && !defined(__LP64__) // OSX Carbon Message Pump do { @@ -214,6 +222,56 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& params.insert(std::make_pair("FSAA", settings.fsaa)); params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); + // Create an application window with the following settings: + SDL_Window *window = SDL_CreateWindow( + "OpenMW", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + settings.window_x, // width, in pixels + settings.window_y, // height, in pixels + SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE + | (settings.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0) + ); + + + //get the native whnd + struct SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version); + + if(-1 == SDL_GetWindowWMInfo(window, &wmInfo)) + throw std::runtime_error("Couldn't get WM Info!"); + + Ogre::String winHandle; + + switch(wmInfo.subsystem) + { +#ifdef WIN32 + case SDL_SYSWM_WINDOWS: + // Windows code + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.win.window); + break; +#elif MACOS + case SDL_SYSWM_COCOA: + //required to make OGRE play nice with our window + params.insert(std::make_pair("macAPI", "cocoa")); + params.insert(std::make_pair("macAPICocoaUseNSView", "true")); + + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.cocoa.window); + break; +#else + case SDL_SYSWM_X11: + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.display); + winHandle += ":0:"; + winHandle += Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.window); + break; +#endif + default: + throw std::runtime_error("Unexpected WM!"); + break; + } + + params.insert(std::make_pair("externalWindowHandle", winHandle)); + mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); // create the semi-transparent black background texture used by the GUI. @@ -253,7 +311,11 @@ void OgreRenderer::createScene(const std::string& camName, float fov, float near void OgreRenderer::adjustViewport() { // Alter the camera aspect ratio to match the viewport - mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); + if(mCamera != NULL) + { + mView->setDimensions(0, 0, 1, 1); + mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); + } } void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index a8788dfca..7e57af927 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -31,6 +31,8 @@ #include #endif +struct SDL_Window; + namespace Ogre { #if !defined(__APPLE__) || defined(__LP64__) @@ -74,6 +76,7 @@ namespace OEngine Ogre::Root *mRoot; #endif Ogre::RenderWindow *mWindow; + SDL_Window *mSDLWindow; Ogre::SceneManager *mScene; Ogre::Camera *mCamera; Ogre::Viewport *mView; @@ -99,6 +102,7 @@ namespace OEngine OgreRenderer() : mRoot(NULL) , mWindow(NULL) + , mSDLWindow(NULL) , mScene(NULL) , mCamera(NULL) , mView(NULL) @@ -169,6 +173,9 @@ namespace OEngine /// Get the rendering window Ogre::RenderWindow *getWindow() { return mWindow; } + /// Get the SDL Window + SDL_Window *getSDLWindow() { return mSDLWindow; } + /// Get the scene manager Ogre::SceneManager *getScene() { return mScene; } From 9b485a86ef8e7f5b96f89b78e5fe6a8f18629cbf Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sun, 13 Jan 2013 22:38:22 -0400 Subject: [PATCH 023/817] resize the window in a slightly less bad way, fix my check in setUseHardwareCursors to be the right way round --- apps/openmw/engine.cpp | 19 ++++--------------- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0619281d0..7d08eda03 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -138,7 +138,7 @@ void OMW::Engine::handleSDLMessages() SDL_PumpEvents(); int num_events = SDL_PeepEvents(events, max_events, SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT); - bool move_or_resize = false; + bool resize = false; unsigned int size_x = 0; unsigned int size_y = 0; @@ -150,9 +150,8 @@ void OMW::Engine::handleSDLMessages() switch(events[i].window.event) { case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_MOVED: printf("Resizing window!\n"); - move_or_resize = true; + resize = true; size_x = events[i].window.data1; size_y = events[i].window.data2; break; @@ -161,23 +160,13 @@ void OMW::Engine::handleSDLMessages() } //handle window movements - if(move_or_resize) + if(resize) { - mOgre->adjustViewport(); if(!mOgre->getWindow()->isFullScreen()) { - SDL_DisplayMode dispMode; - SDL_Window* sdlWindow = mOgre->getSDLWindow(); - - SDL_GetWindowDisplayMode(sdlWindow, &dispMode); - - dispMode.w = size_x; - dispMode.h = size_y; - - SDL_SetWindowDisplayMode(sdlWindow, &dispMode); - mOgre->getWindow()->windowMovedOrResized(); mOgre->getWindow()->resize(size_x, size_y); + mOgre->adjustViewport(); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e096ee1fb..dbd8e01a2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -750,7 +750,7 @@ void WindowManager::setUseHardwareCursors(bool use) { mCursorManager->setEnabled(use); - if(!use) + if(use) { MyGUI::PointerManager::getInstance().setVisible(false); } From 10a3caa50494b0abe3776496fb72dcd5ef73d4f0 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sun, 13 Jan 2013 23:38:46 -0400 Subject: [PATCH 024/817] more resizing fixes from scrawl, share an SDLWindow between the input wrapper and the engine --- apps/openmw/engine.cpp | 10 +---- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +-- apps/openmw/mwinput/inputmanagerimp.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 1 - extern/sdl4ogre/sdlinputwrapper.cpp | 49 ++++++++++++++--------- extern/sdl4ogre/sdlinputwrapper.hpp | 6 ++- libs/openengine/ogre/renderer.cpp | 4 +- 7 files changed, 39 insertions(+), 37 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7d08eda03..3374ba304 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -150,7 +150,6 @@ void OMW::Engine::handleSDLMessages() switch(events[i].window.event) { case SDL_WINDOWEVENT_RESIZED: - printf("Resizing window!\n"); resize = true; size_x = events[i].window.data1; size_y = events[i].window.data2; @@ -162,12 +161,7 @@ void OMW::Engine::handleSDLMessages() //handle window movements if(resize) { - if(!mOgre->getWindow()->isFullScreen()) - { - mOgre->getWindow()->windowMovedOrResized(); - mOgre->getWindow()->resize(size_x, size_y); - mOgre->adjustViewport(); - } + mOgre->getWindow()->resize(size_x, size_y); } if(SDL_PeepEvents(NULL, 1, SDL_PEEKEVENT, SDL_QUIT, SDL_QUIT) != 0) @@ -436,7 +430,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, MWBase::Environment::get().getWorld()->getPlayer(), - *MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists)); + *MWBase::Environment::get().getWindowManager(), *this, keybinderUser, keybinderUserExists)); // load cell ESM::Position pos; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9d80de91e..ab873c686 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -31,7 +31,6 @@ namespace MWInput InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, MWWorld::Player &player, MWBase::WindowManager &windows, - bool debug, OMW::Engine& engine, const std::string& userFile, bool userFileExists) : mOgre(ogre) @@ -45,7 +44,7 @@ namespace MWInput , mUserFile(userFile) , mDragDrop(false) , mGuiCursorEnabled(false) - , mDebug(debug) + , mDebug(Settings::Manager::getBool("debug", "Engine")) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) @@ -63,7 +62,7 @@ namespace MWInput Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new SFO::InputWrapper(window); + mInputManager = new SFO::InputWrapper(mOgre.getSDLWindow()); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 34ea92a37..9832be9a6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -62,7 +62,6 @@ namespace MWInput InputManager(OEngine::Render::OgreRenderer &_ogre, MWWorld::Player&_player, MWBase::WindowManager &_windows, - bool debug, OMW::Engine& engine, const std::string& userFile, bool userFileExists); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ae7d6612b..5d2a5c951 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -839,7 +839,6 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw) Settings::Manager::setInt("resolution x", "Video", rw->getWidth()); Settings::Manager::setInt("resolution y", "Video", rw->getHeight()); - mRendering.adjustViewport(); mCompositors->recreate(); mWater->assignTextures(); diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index cf864b20f..464d8cb6a 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -16,9 +16,9 @@ namespace SFO { /// \brief General purpose wrapper for OGRE applications around SDL's event /// queue, mostly used for handling input-related events. - InputWrapper::InputWrapper(Ogre::RenderWindow *window) : - mWindow(window), - mSDLWindow(NULL), + InputWrapper::InputWrapper(SDL_Window* window) : + mSDLWindow(window), + mOwnWindow(false), mWarpCompensate(false), mMouseRelative(false), mGrabPointer(false), @@ -29,9 +29,27 @@ namespace SFO { _setupOISKeys(); + SDL_StartTextInput(); + } + + InputWrapper::~InputWrapper() + { + if(mSDLWindow != NULL && mOwnWindow) + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + + SDL_StopTextInput(); + } + + void InputWrapper::initFromRenderWindow(Ogre::RenderWindow *win) + { + assert(mSDLWindow == NULL); + + mOwnWindow = true; + //get the HWND from ogre's renderwindow size_t windowHnd; - mWindow->getCustomAttribute("WINDOW", &windowHnd); + win->getCustomAttribute("WINDOW", &windowHnd); //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); @@ -42,9 +60,6 @@ namespace SFO //we alt-tab away. //SDL_SetWindowFullscreen(mSDLWindow, 0); - //translate our keypresses into text - SDL_StartTextInput(); - #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX //linux-specific event-handling fixups //see http://bugzilla.libsdl.org/show_bug.cgi?id=730 @@ -78,15 +93,6 @@ namespace SFO #endif } - InputWrapper::~InputWrapper() - { - if(mSDLWindow != NULL) - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; - - SDL_StopTextInput(); - } - void InputWrapper::capture() { SDL_Event evt; @@ -158,11 +164,14 @@ namespace SFO //eep, wrap the pointer manually if the input driver doesn't support //relative positioning natively - SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE); + int success = SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE); if(relative) { - mWrapPointer = true; + if(success != 0) + { + mWrapPointer = true; + } } //now remove all mouse events using the old setting from the queue @@ -200,8 +209,8 @@ namespace SFO SDL_GetWindowSize(mSDLWindow, &width, &height); - const int FUDGE_FACTOR_X = width / 4; - const int FUDGE_FACTOR_Y = height / 4; + const int FUDGE_FACTOR_X = width / 8; + const int FUDGE_FACTOR_Y = height / 8; //warp the mouse if it's about to go outside the window if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 9154ff847..db4e6f9b0 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -16,9 +16,11 @@ namespace SFO class InputWrapper { public: - InputWrapper(Ogre::RenderWindow* window); + InputWrapper(SDL_Window *window=NULL); ~InputWrapper(); + void initFromRenderWindow(Ogre::RenderWindow* win); + void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } @@ -62,8 +64,8 @@ namespace SFO Sint32 mMouseX; Sint32 mMouseY; - Ogre::RenderWindow* mWindow; SDL_Window* mSDLWindow; + bool mOwnWindow; }; } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 7696095eb..0f29b15a0 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -223,7 +223,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); // Create an application window with the following settings: - SDL_Window *window = SDL_CreateWindow( + mSDLWindow = SDL_CreateWindow( "OpenMW", // window title SDL_WINDOWPOS_UNDEFINED, // initial x position SDL_WINDOWPOS_UNDEFINED, // initial y position @@ -238,7 +238,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& struct SDL_SysWMinfo wmInfo; SDL_VERSION(&wmInfo.version); - if(-1 == SDL_GetWindowWMInfo(window, &wmInfo)) + if(-1 == SDL_GetWindowWMInfo(mSDLWindow, &wmInfo)) throw std::runtime_error("Couldn't get WM Info!"); Ogre::String winHandle; From 5fc7103425732403a0b8e6f092430a2996138488 Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 20:31:47 +0000 Subject: [PATCH 025/817] First attempt at pathfinding using boost::graph --- apps/openmw/mwmechanics/aitravel.cpp | 193 ++++++++++++++++++++++++++- apps/openmw/mwmechanics/aitravel.hpp | 7 +- 2 files changed, 196 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 897dd1748..b5e67e449 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,8 +1,19 @@ #include "aitravel.hpp" #include +#include "character.hpp" + +#include "../mwworld/class.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "movement.hpp" + +#include +#include +#include "boost/tuple/tuple.hpp" + MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z) +: mX(x),mY(y),mZ(z),isPathConstructed(false) { } @@ -11,10 +22,186 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } +float distance(ESM::Pathgrid::Point point,float x,float y,float z) +{ + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); +} + +float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) +{ + return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); +} + +int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) +{ + if(!grid) throw std::exception("NULL PathGrid!"); + if(grid->mPoints.empty()) throw std::exception("empty PathGrid!"); + + float m = distance(grid->mPoints[0],x,y,z); + int i0 = 0; + + for(int i=1; imPoints.size();i++) + { + if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); + i0 = i; + } + } + + return i0; +} + +float sgn(float a) +{ + if(a>0) return 1.; + else return -1.; +} + +float getZAngle(float dX,float dY) +{ + float h = sqrt(dX*dX+dY*dY); + return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); +} + +struct Edge +{ + float distance; +}; + +typedef boost::adjacency_list,boost::property > PathGridGraph; +typedef boost::property_map::type WeightMap; +typedef PathGridGraph::vertex_descriptor PointID; +typedef PathGridGraph::edge_descriptor PointConnectionID; + +struct found_path {}; + +class goalVisited : public boost::default_astar_visitor +{ +public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } +private: + PointID mGoal; +}; + +class DistanceHeuristic : public boost::astar_heuristic +{ +public: + DistanceHeuristic(const PathGridGraph & l, PointID goal) + : mGraph(l), mGoal(goal) {} + + float operator()(PointID u) + { + const ESM::Pathgrid::Point & U = mGraph[u]; + const ESM::Pathgrid::Point & V = mGraph[mGoal]; + float dx = U.mX - V.mX; + float dy = U.mY - V.mY; + float dz = U.mZ - V.mZ; + return sqrt(dx * dx + dy * dy + dz * dz); + } +private: + const PathGridGraph & mGraph; + PointID mGoal; +}; + +std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::vector p(boost::num_vertices(graph)); + std::vector d(boost::num_vertices(graph)); + std::list shortest_path; + + try { + boost::astar_search + ( + graph, + start, + DistanceHeuristic(graph,end), + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) + ); + + } catch(found_path fg) { + for(PointID v = end;; v = p[v]) { + shortest_path.push_front(graph[v]); + if(p[v] == v) + break; + } + } + return shortest_path; +} + +PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid) +{ + PathGridGraph graph; + + for(int i = 0;imPoints.size();i++) + { + PointID pID = boost::add_vertex(graph); + graph[pID] = pathgrid->mPoints[i]; + } + + for(int i = 0;imEdges.size();i++) + { + PointID u = pathgrid->mEdges[i].mV0; + PointID v = pathgrid->mEdges[i].mV1; + + PointConnectionID edge; + bool done; + boost::tie(edge,done) = boost::add_edge(u,v,graph); + WeightMap weightmap = boost::get(boost::edge_weight, graph); + weightmap[edge] = distance(graph[u],graph[v]); + + } + + return graph; +} + bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { - std::cout << "AiTravel completed.\n"; - return true; + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + ESM::Position pos = actor.getRefData().getPosition(); + + if(!isPathConstructed) + { + int start = getClosestPoint(pathgrid,pos.pos[0],pos.pos[1],pos.pos[2]); + int end = getClosestPoint(pathgrid,mX,mY,mZ); + + PathGridGraph graph = buildGraph(pathgrid); + + mPath = getPath(start,end,graph); + isPathConstructed = true; + } + if(mPath.empty()) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + if(distance(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) + { + mPath.pop_front(); + if(mPath.empty()) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + nextPoint = *mPath.begin(); + } + + float dX = nextPoint.mX - pos.pos[0]; + float dY = nextPoint.mY - pos.pos[1]; + + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + return false; + //return true; } int MWMechanics::AiTravel::getTypeId() const diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 1c6abbf27..a596f4c85 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,7 +1,9 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H -#include "aipackage.hpp" +#include "aipackage.hpp" +#include "components\esm\loadpgrd.hpp" +#include namespace MWMechanics { @@ -21,6 +23,9 @@ namespace MWMechanics float mY; float mZ; + bool isPathConstructed; + std::list mPath; + }; } From 01908dbcc27f2202e13dce90fe24f77dc268c97c Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 21:17:33 +0000 Subject: [PATCH 026/817] little improvement --- apps/openmw/mwmechanics/aitravel.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b5e67e449..9d41a080c 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -22,6 +22,11 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } +float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) +{ + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); +} + float distance(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); @@ -64,11 +69,6 @@ float getZAngle(float dX,float dY) return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); } -struct Edge -{ - float distance; -}; - typedef boost::adjacency_list,boost::property > PathGridGraph; typedef boost::property_map::type WeightMap; @@ -176,6 +176,11 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) PathGridGraph graph = buildGraph(pathgrid); mPath = getPath(start,end,graph); + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + mPath.push_back(dest); isPathConstructed = true; } if(mPath.empty()) @@ -184,7 +189,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distance(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) + if(distanceZCorrected(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) { mPath.pop_front(); if(mPath.empty()) From bbc4c23f7e184782eec35bface3e0d10df182dd1 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 10 Mar 2013 15:07:22 +0000 Subject: [PATCH 027/817] AITravel now works correctly on exterior cells. As long as NPC don't try to leave cell, it's ok. --- apps/openmw/mwmechanics/aitravel.cpp | 31 ++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 9d41a080c..09b0efad9 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -53,7 +53,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) i0 = i; } } - + std::cout << "distance:: " << m << "\n"; return i0; } @@ -135,14 +135,16 @@ std::list getPath(PointID start,PointID end,PathGridGraph return shortest_path; } -PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid) +PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; for(int i = 0;imPoints.size();i++) { PointID pID = boost::add_vertex(graph); - graph[pID] = pathgrid->mPoints[i]; + graph[pID].mX = pathgrid->mPoints[i].mX + xCell; + graph[pID].mY = pathgrid->mPoints[i].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[i].mZ; } for(int i = 0;imEdges.size();i++) @@ -165,17 +167,26 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - ESM::Position pos = actor.getRefData().getPosition(); + ESM::Position pos = actor.getRefData().getPosition(); + //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } - PathGridGraph graph = buildGraph(pathgrid); + int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); + int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); + + PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); mPath = getPath(start,end,graph); + if(mPath.empty()) std::cout << "graph doesn't find any way..."; ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; @@ -185,6 +196,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(mPath.empty()) { + std::cout << "pathc empty"; MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } @@ -195,6 +207,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) if(mPath.empty()) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + std::cout << "emptypath!"; return true; } nextPoint = *mPath.begin(); @@ -205,8 +218,8 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + return false; - //return true; } int MWMechanics::AiTravel::getTypeId() const From f943580138209a27497e0613ab6914f5194a3589 Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 12 Mar 2013 17:44:22 +0000 Subject: [PATCH 028/817] Somehow manages to get from one cell to another, but this looks wrong... And I don't know how morrowind do it, because aitravel is completly buggy --- apps/openmw/mwmechanics/aitravel.cpp | 6 +++++- apps/openmw/mwmechanics/aitravel.hpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 09b0efad9..3c2e29743 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -169,9 +169,13 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + if(cellChange) std::cout << "cellChanged! \n"; //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; float yCell = 0; if (actor.getCell()->mCell->isExterior()) diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index a596f4c85..3d220cb7e 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -23,6 +23,9 @@ namespace MWMechanics float mY; float mZ; + int cellX; + int cellY; + bool isPathConstructed; std::list mPath; From 80804fac351fedcde4735753c7ae2db461a80628 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 14 Mar 2013 17:16:37 +0000 Subject: [PATCH 029/817] check if the NPC is close from a non loaded cell. If yes, AITravel is simply ended. --- apps/openmw/mwmechanics/aitravel.cpp | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 3c2e29743..57b9f66dd 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -7,6 +7,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "movement.hpp" +#include "../mwworld/player.hpp" #include #include @@ -167,13 +168,35 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - if(cellChange) std::cout << "cellChanged! \n"; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; @@ -190,7 +213,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); mPath = getPath(start,end,graph); - if(mPath.empty()) std::cout << "graph doesn't find any way..."; + ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; @@ -200,7 +223,6 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(mPath.empty()) { - std::cout << "pathc empty"; MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } @@ -211,7 +233,6 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) if(mPath.empty()) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - std::cout << "emptypath!"; return true; } nextPoint = *mPath.begin(); From 9efb073617cf41f66f774c9453574594fbcf2870 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 14 Mar 2013 18:05:00 +0000 Subject: [PATCH 030/817] clean up + correct a bug --- apps/openmw/mwmechanics/aitravel.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 57b9f66dd..94f6fd892 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -40,8 +40,8 @@ float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) { - if(!grid) throw std::exception("NULL PathGrid!"); - if(grid->mPoints.empty()) throw std::exception("empty PathGrid!"); + if(!grid) return -1; + if(grid->mPoints.empty()) return -1; float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; @@ -54,7 +54,6 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) i0 = i; } } - std::cout << "distance:: " << m << "\n"; return i0; } @@ -175,7 +174,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) { - int sideX = sgn(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX); + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) { @@ -185,7 +184,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) { - int sideY = sgn(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY); + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) { @@ -193,10 +192,9 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } } - //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; @@ -210,9 +208,11 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); - PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); - - mPath = getPath(start,end,graph); + if(start != -1 && end != -1) + { + PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); + mPath = getPath(start,end,graph); + } ESM::Pathgrid::Point dest; dest.mX = mX; From 3731ec0541998dab62ee0cf464ddaca4f03237ef Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 21 Mar 2013 19:54:26 +0100 Subject: [PATCH 031/817] Praying to God. --- files/opencs/scalable/Palette.svg | 569 ++++++ .../referenceable record type/.directory | 5 + .../referenceable record type/activator.svg | 1088 ++++++++++++ .../referenceable record type/apparatus.svg | 1058 +++++++++++ .../referenceable record type/book.svg | 692 ++++++++ .../referenceable record type/container.svg | 1359 +++++++++++++++ .../light source.svg | 1543 +++++++++++++++++ .../referenceable record type/potion.svg | 1052 +++++++++++ .../referenceable record type/static.svg | 1141 ++++++++++++ .../referenceable record type/weapon.svg | 1175 +++++++++++++ 10 files changed, 9682 insertions(+) create mode 100644 files/opencs/scalable/Palette.svg create mode 100644 files/opencs/scalable/referenceable record type/.directory create mode 100644 files/opencs/scalable/referenceable record type/activator.svg create mode 100644 files/opencs/scalable/referenceable record type/apparatus.svg create mode 100644 files/opencs/scalable/referenceable record type/book.svg create mode 100644 files/opencs/scalable/referenceable record type/container.svg create mode 100644 files/opencs/scalable/referenceable record type/light source.svg create mode 100644 files/opencs/scalable/referenceable record type/potion.svg create mode 100644 files/opencs/scalable/referenceable record type/static.svg create mode 100644 files/opencs/scalable/referenceable record type/weapon.svg diff --git a/files/opencs/scalable/Palette.svg b/files/opencs/scalable/Palette.svg new file mode 100644 index 000000000..f42475330 --- /dev/null +++ b/files/opencs/scalable/Palette.svg @@ -0,0 +1,569 @@ + + + + + + + image/svg+xml + + + + + + Tango Palette + + + Tuomas Kuosmanen + + + + + Garrett Le Sage +Kenneth Wimer +Jakub Steiner + + +http://www.tango-project.org/files/Tango-Palette.svg + + + unify + global + theme + color + palette + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/files/opencs/scalable/referenceable record type/.directory b/files/opencs/scalable/referenceable record type/.directory new file mode 100644 index 000000000..e2d80ed58 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/referenceable record type/activator.svg b/files/opencs/scalable/referenceable record type/activator.svg new file mode 100644 index 000000000..0c6db59a7 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/activator.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/apparatus.svg b/files/opencs/scalable/referenceable record type/apparatus.svg new file mode 100644 index 000000000..37cef0e89 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/apparatus.svg @@ -0,0 +1,1058 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/book.svg b/files/opencs/scalable/referenceable record type/book.svg new file mode 100644 index 000000000..8c041a9e7 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/book.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg new file mode 100644 index 000000000..11ad79438 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -0,0 +1,1359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/light source.svg b/files/opencs/scalable/referenceable record type/light source.svg new file mode 100644 index 000000000..8575659f4 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/light source.svg @@ -0,0 +1,1543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg new file mode 100644 index 000000000..888006531 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/potion.svg @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/static.svg b/files/opencs/scalable/referenceable record type/static.svg new file mode 100644 index 000000000..a6f29370f --- /dev/null +++ b/files/opencs/scalable/referenceable record type/static.svg @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/weapon.svg b/files/opencs/scalable/referenceable record type/weapon.svg new file mode 100644 index 000000000..1e5aaac41 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/weapon.svg @@ -0,0 +1,1175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + From e46097cd2ed1e1742d63a2d958c8cec6a68645f1 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 21 Mar 2013 19:54:26 +0100 Subject: [PATCH 032/817] Icons. Currently activator, apparatus, book, container (work in progress), light source, potion, static, weapon. --- files/opencs/scalable/Palette.svg | 569 ++++++ .../referenceable record type/.directory | 5 + .../referenceable record type/activator.svg | 1088 ++++++++++++ .../referenceable record type/apparatus.svg | 1058 +++++++++++ .../referenceable record type/book.svg | 692 ++++++++ .../referenceable record type/container.svg | 1359 +++++++++++++++ .../light source.svg | 1543 +++++++++++++++++ .../referenceable record type/potion.svg | 1052 +++++++++++ .../referenceable record type/static.svg | 1141 ++++++++++++ .../referenceable record type/weapon.svg | 1175 +++++++++++++ 10 files changed, 9682 insertions(+) create mode 100644 files/opencs/scalable/Palette.svg create mode 100644 files/opencs/scalable/referenceable record type/.directory create mode 100644 files/opencs/scalable/referenceable record type/activator.svg create mode 100644 files/opencs/scalable/referenceable record type/apparatus.svg create mode 100644 files/opencs/scalable/referenceable record type/book.svg create mode 100644 files/opencs/scalable/referenceable record type/container.svg create mode 100644 files/opencs/scalable/referenceable record type/light source.svg create mode 100644 files/opencs/scalable/referenceable record type/potion.svg create mode 100644 files/opencs/scalable/referenceable record type/static.svg create mode 100644 files/opencs/scalable/referenceable record type/weapon.svg diff --git a/files/opencs/scalable/Palette.svg b/files/opencs/scalable/Palette.svg new file mode 100644 index 000000000..f42475330 --- /dev/null +++ b/files/opencs/scalable/Palette.svg @@ -0,0 +1,569 @@ + + + + + + + image/svg+xml + + + + + + Tango Palette + + + Tuomas Kuosmanen + + + + + Garrett Le Sage +Kenneth Wimer +Jakub Steiner + + +http://www.tango-project.org/files/Tango-Palette.svg + + + unify + global + theme + color + palette + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/files/opencs/scalable/referenceable record type/.directory b/files/opencs/scalable/referenceable record type/.directory new file mode 100644 index 000000000..e2d80ed58 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/referenceable record type/activator.svg b/files/opencs/scalable/referenceable record type/activator.svg new file mode 100644 index 000000000..0c6db59a7 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/activator.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/apparatus.svg b/files/opencs/scalable/referenceable record type/apparatus.svg new file mode 100644 index 000000000..37cef0e89 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/apparatus.svg @@ -0,0 +1,1058 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/book.svg b/files/opencs/scalable/referenceable record type/book.svg new file mode 100644 index 000000000..8c041a9e7 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/book.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg new file mode 100644 index 000000000..11ad79438 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -0,0 +1,1359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/light source.svg b/files/opencs/scalable/referenceable record type/light source.svg new file mode 100644 index 000000000..8575659f4 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/light source.svg @@ -0,0 +1,1543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg new file mode 100644 index 000000000..888006531 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/potion.svg @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/static.svg b/files/opencs/scalable/referenceable record type/static.svg new file mode 100644 index 000000000..a6f29370f --- /dev/null +++ b/files/opencs/scalable/referenceable record type/static.svg @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/weapon.svg b/files/opencs/scalable/referenceable record type/weapon.svg new file mode 100644 index 000000000..1e5aaac41 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/weapon.svg @@ -0,0 +1,1175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + From df8600e636082eb6c7821c51b7dd49ac1062e0d7 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 22 Mar 2013 18:06:11 +0100 Subject: [PATCH 033/817] New anvil icon (repair.svg), edited weapon.svg (added new gradient on dagger blade) and light source.svg (clear to see what happend). container icon is still work in progress. --- .../light source.svg | 136 +- .../referenceable record type/repair.svg | 1280 +++++++++++++++++ .../referenceable record type/weapon.svg | 37 +- 3 files changed, 1367 insertions(+), 86 deletions(-) create mode 100644 files/opencs/scalable/referenceable record type/repair.svg diff --git a/files/opencs/scalable/referenceable record type/light source.svg b/files/opencs/scalable/referenceable record type/light source.svg index 8575659f4..f8f506636 100644 --- a/files/opencs/scalable/referenceable record type/light source.svg +++ b/files/opencs/scalable/referenceable record type/light source.svg @@ -23,11 +23,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="5.12" - inkscape:cx="-14.844087" - inkscape:cy="12.523576" + inkscape:zoom="7.2407734" + inkscape:cx="15.039623" + inkscape:cy="28.976292" inkscape:document-units="px" - inkscape:current-layer="g4512" + inkscape:current-layer="g6692" showgrid="true" showguides="true" inkscape:guide-bbox="true" @@ -45,9 +45,9 @@ inkscape:object-paths="true" inkscape:snap-intersection-paths="true" inkscape:object-nodes="true" - inkscape:snap-global="true" + inkscape:snap-global="false" inkscape:snap-smooth-nodes="false" - inkscape:snap-grids="false" + inkscape:snap-grids="true" inkscape:snap-nodes="true"> + + + + + + + + + - - - @@ -1448,29 +1441,14 @@ - - + d="m 32.999997,6.5 a 6.4999967,2.5 0 1 1 -12.999994,0 6.4999967,2.5 0 1 1 12.999994,0 z" + transform="matrix(1.2476493,0,0,1.1773057,-95.452015,955.91965)" /> - + width="1.1570125" + height="2.2736316" + x="-62.967812" + y="961.29846" /> + d="m -50.291451,955.99365 c -0.306142,0.58022 -0.173213,1.37959 -0.741985,1.81489 -0.555003,0.71326 -0.773186,1.6155 -1.259884,2.37061 -0.545654,1.01279 -0.9642,2.21153 -0.612129,3.35954 0.288553,1.36917 0.604843,2.81123 1.512357,3.91947 0.601372,0.6775 1.7644,0.89162 2.455823,0.22684 0.753966,-0.66641 1.219278,-1.61104 1.490732,-2.56706 0.268644,-1.09118 0.258571,-2.22309 0.405108,-3.33193 0.004,-0.92336 -0.539155,-1.718 -0.841509,-2.56039 -0.468277,-1.04235 -0.941776,-2.14938 -1.812123,-2.9223 -0.181111,-0.13328 -0.382557,-0.23957 -0.59639,-0.30967 z" + style="fill:#ffcb80;fill-opacity:1;stroke:none;filter:url(#filter4579)" + transform="matrix(1.1359383,0,0,1.1359383,-5.573807,-136.87442)" /> - + d="m -50.089487,965.64147 c -0.06194,0.11739 -0.03504,0.2791 -0.150109,0.36717 -0.11228,0.14429 -0.15642,0.32682 -0.254882,0.47959 -0.110389,0.20489 -0.195064,0.4474 -0.123837,0.67965 0.05838,0.27699 0.122363,0.56873 0.305959,0.79293 0.121661,0.13707 0.356949,0.18038 0.496828,0.0459 0.152532,-0.13481 0.246667,-0.32592 0.301584,-0.51933 0.05435,-0.22075 0.05231,-0.44974 0.08196,-0.67406 8.27e-4,-0.18681 -0.109074,-0.34757 -0.170242,-0.51799 -0.09474,-0.21087 -0.190528,-0.43483 -0.366604,-0.5912 -0.03664,-0.0269 -0.07739,-0.0485 -0.120653,-0.0626 z" + style="fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter4575)" + transform="matrix(1.1359383,0,0,1.1359383,-5.573807,-136.87442)" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/weapon.svg b/files/opencs/scalable/referenceable record type/weapon.svg index 1e5aaac41..2e832fff7 100644 --- a/files/opencs/scalable/referenceable record type/weapon.svg +++ b/files/opencs/scalable/referenceable record type/weapon.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="3.6203867" - inkscape:cx="-21.028476" - inkscape:cy="-1.6134251" + inkscape:zoom="5.12" + inkscape:cx="13.777504" + inkscape:cy="9.2319835" inkscape:document-units="px" inkscape:current-layer="g5966" showgrid="true" @@ -56,6 +56,17 @@ + + + + + @@ -1170,6 +1190,17 @@ d="m -69.333164,982.81214 0,3.65905 -6.823877,0 11.138217,11.04103 11.138216,-11.04103 -6.823877,0 0,-3.65905 -8.628679,0 z" id="path5146" inkscape:connector-curvature="0" /> + + + + From 001b56714a2da5efdbe940b5a06645a5fa863596 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 23 Mar 2013 16:16:23 +0100 Subject: [PATCH 034/817] Adding new status icons svg files. Qt svg does not allow blur to be used so I think that we should make png files of it but first information on the actual resolution needed is required... --- files/opencs/scalable/status/.directory | 5 + files/opencs/scalable/status/added.svg | 917 ++++++++++++++++ files/opencs/scalable/status/modified.svg | 1197 +++++++++++++++++++++ files/opencs/scalable/status/removed.svg | 1088 +++++++++++++++++++ 4 files changed, 3207 insertions(+) create mode 100644 files/opencs/scalable/status/.directory create mode 100644 files/opencs/scalable/status/added.svg create mode 100644 files/opencs/scalable/status/modified.svg create mode 100644 files/opencs/scalable/status/removed.svg diff --git a/files/opencs/scalable/status/.directory b/files/opencs/scalable/status/.directory new file mode 100644 index 000000000..e2d80ed58 --- /dev/null +++ b/files/opencs/scalable/status/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/status/added.svg b/files/opencs/scalable/status/added.svg new file mode 100644 index 000000000..a5767d23b --- /dev/null +++ b/files/opencs/scalable/status/added.svg @@ -0,0 +1,917 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/files/opencs/scalable/status/modified.svg b/files/opencs/scalable/status/modified.svg new file mode 100644 index 000000000..c8b56cd04 --- /dev/null +++ b/files/opencs/scalable/status/modified.svg @@ -0,0 +1,1197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/files/opencs/scalable/status/removed.svg b/files/opencs/scalable/status/removed.svg new file mode 100644 index 000000000..719035be9 --- /dev/null +++ b/files/opencs/scalable/status/removed.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + From 43e863b0207396bf68ce868c11077cb7ba3f3b54 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 23 Mar 2013 16:22:17 +0100 Subject: [PATCH 035/817] Forgot to place the icons in the middle of the page. --- files/opencs/scalable/status/modified.svg | 67 ++----------------- files/opencs/scalable/status/removed.svg | 80 +++-------------------- 2 files changed, 13 insertions(+), 134 deletions(-) diff --git a/files/opencs/scalable/status/modified.svg b/files/opencs/scalable/status/modified.svg index c8b56cd04..3b183e314 100644 --- a/files/opencs/scalable/status/modified.svg +++ b/files/opencs/scalable/status/modified.svg @@ -24,8 +24,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="3.6203867" - inkscape:cx="-21.788854" - inkscape:cy="23.355872" + inkscape:cx="-39.987384" + inkscape:cy="43.542041" inkscape:document-units="px" inkscape:current-layer="g5966" showgrid="true" @@ -985,16 +985,6 @@ fx="-97.089668" fy="-33.913769" r="20" /> - - - - - - @@ -1140,7 +1083,7 @@ transform="matrix(0.97772023,0,0,0.97772023,100.68016,77.074325)"> - - - - - - - - + transform="matrix(0,1,-1,0,0.20564565,0.22375836)" /> + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4.5731945;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + transform="matrix(0,1,-1,0,0.20564565,0.22375836)" /> From 59233e54b2083afd72d250928e7060de0d2a3419 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 23 Mar 2013 18:18:19 +0100 Subject: [PATCH 036/817] changing potion.svg according to pvdk sugestions --- .../referenceable record type/potion.svg | 162 +++++++++++------- 1 file changed, 104 insertions(+), 58 deletions(-) diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg index 888006531..612f45aa4 100644 --- a/files/opencs/scalable/referenceable record type/potion.svg +++ b/files/opencs/scalable/referenceable record type/potion.svg @@ -24,10 +24,10 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7.2407734" - inkscape:cx="18.842132" - inkscape:cy="26.695499" + inkscape:cx="3.6117613" + inkscape:cy="14.120537" inkscape:document-units="px" - inkscape:current-layer="g5966" + inkscape:current-layer="g3910" showgrid="true" showguides="true" inkscape:guide-bbox="true" @@ -55,6 +55,32 @@ + + + + + + + + + - + offset="0" + style="stop-color:#8cf0eb;stop-opacity:0.78431374;" /> @@ -930,22 +952,12 @@ fx="-150.6485" fy="-33.680485" r="19.749271" /> - + xlink:href="#linearGradient3853" + id="radialGradient3918" + cx="0.20415781" + cy="26.466549" + fx="0.20415781" + fy="26.466549" + r="15.52295" + gradientTransform="matrix(1.3421662,-1.1488417,0.96457332,1.1859542,-25.598784,-3.3438458)" + gradientUnits="userSpaceOnUse" /> + + + xlink:href="#linearGradient4535" + id="radialGradient4543" + cx="15.546875" + cy="24" + fx="15.546875" + fy="24" + r="15.52295" + gradientTransform="matrix(0.99999999,-0.04184496,0.06136199,1.5432733,-1.4726875,-12.388)" + gradientUnits="userSpaceOnUse" /> @@ -1017,30 +1047,46 @@ sodipodi:ry="4.4194174" d="m -133.13494,-22.158251 c 0,2.440777 -8.84205,4.419418 -19.74928,4.419418 -10.90722,0 -19.74927,-1.978641 -19.74927,-4.419418 0,-2.440777 8.84205,-4.419417 19.74927,-4.419417 10.90723,0 19.74928,1.97864 19.74928,4.419417 z" transform="matrix(0.92927807,0,0,1.0003876,63.663518,999.66077)" /> - + + + + + + - - Date: Sat, 23 Mar 2013 19:29:52 +0100 Subject: [PATCH 037/817] Drawer as container icon. Look a little better the old crappy chest but changes are needed. --- .../referenceable record type/container.svg | 2217 +++++++++-------- 1 file changed, 1223 insertions(+), 994 deletions(-) diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg index 11ad79438..2a93954bd 100644 --- a/files/opencs/scalable/referenceable record type/container.svg +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="11.313709" - inkscape:cx="20.32374" - inkscape:cy="21.784699" + inkscape:zoom="8.0000004" + inkscape:cx="7.2255179" + inkscape:cy="2.9394873" inkscape:document-units="px" inkscape:current-layer="g9364" showgrid="true" @@ -43,1219 +43,1477 @@ inkscape:snap-bbox-edge-midpoints="false" inkscape:snap-bbox-midpoints="false" inkscape:object-paths="true" - inkscape:snap-intersection-paths="false" + inkscape:snap-intersection-paths="true" inkscape:object-nodes="true" inkscape:snap-global="true" - inkscape:snap-smooth-nodes="false" + inkscape:snap-smooth-nodes="true" inkscape:snap-grids="false" inkscape:snap-nodes="true" inkscape:snap-midpoints="false"> + type="xygrid" + id="grid3225" /> + + + + + id="linearGradient6181" + inkscape:collect="always"> + style="stop-color:#232323;stop-opacity:1;" /> + + + + + + + + + + + + + + style="stop-color:#000000;stop-opacity:1;" /> + + + + + + + + + + + + + + + + + + style="stop-color:#000e50;stop-opacity:1;" /> + style="stop-color:#002bf4;stop-opacity:1;" /> + style="stop-color:#ffcb80;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:1;" /> + id="stop8862" /> + id="stop8864" /> + id="stop8852" /> + style="stop-color:#ffffff;stop-opacity:1;" /> + id="stop8834" /> + id="stop8836" /> + id="stop4482" /> + id="stop4484" /> + inkscape:collect="always" + id="linearGradient3882"> + id="stop3884" /> + id="stop3886" /> + id="stop3941" /> + id="stop3943" /> + id="stop3881" /> + id="stop3883" /> + id="stop3869" /> + id="stop3871" /> + id="stop3855" /> + style="stop-color:#caf8db;stop-opacity:0.58823532;" /> + id="stop3857" /> + id="stop3847" /> + id="stop3849" /> + id="stop3839" /> + id="stop3841" /> + inkscape:collect="always" + id="linearGradient5958"> + id="stop5960" /> + id="stop5962" /> + id="stop5924" /> + id="stop5926" /> + style="stop-color:#000000;stop-opacity:1;" /> + id="stop6825" /> + style="stop-color:#3c3c3c;stop-opacity:0;" /> + style="stop-color:#204a87;stop-opacity:1;" /> + style="stop-color:#729fcf;stop-opacity:1;" /> + style="stop-color:#ffffff;stop-opacity:0.78431374;" /> + style="stop-color:#ffffff;stop-opacity:0;" /> + style="stop-color:#99bbd4;stop-opacity:1;" /> + style="stop-color:#5d93ba;stop-opacity:1;" /> + style="stop-color:#a6c4d9;stop-opacity:0.78431374;" /> + style="stop-color:#75a3c3;stop-opacity:1;" /> - + - - - - - - - - - - - - - + + + + + + + + + + + + + + id="stop3820" /> + id="stop3822" /> + fx="-171.01654" + cy="123.88583" + cx="-171.01654" + gradientTransform="matrix(0.23290796,0.98292589,-1.5211573,0.36044393,244.44953,1091.8596)" + gradientUnits="userSpaceOnUse" + id="radialGradient5639" + xlink:href="#linearGradient3715-2" + inkscape:collect="always" /> + id="stop3717-4" /> + id="stop3719-9" /> + fx="-182.4375" + cy="116.19179" + cx="-182.4375" + gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,227.36718,1219.3395)" + gradientUnits="userSpaceOnUse" + id="radialGradient5641" + xlink:href="#linearGradient5299" + inkscape:collect="always" /> + id="stop5301" /> + id="stop5303" /> + fx="-172.875" + cy="119.59179" + cx="-172.875" + gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,240.54684,45.0811)" + gradientUnits="userSpaceOnUse" + id="radialGradient6812" + xlink:href="#linearGradient3715-2" + inkscape:collect="always" /> + x2="26.643335" + y1="39.630547" + x1="27.183681" + id="linearGradient6823" + xlink:href="#linearGradient6815" + inkscape:collect="always" + gradientTransform="translate(8.4245144,951.32919)" /> + + + + + - - - - - - + gradientTransform="matrix(-0.28231332,0,0,0.28231332,64.982195,664.15172)" + x1="63.765881" + y1="941.44623" + x2="63.765881" + y2="965.56183" /> + + style="stop-color:#000000;stop-opacity:1;" /> + id="stop6825-9" /> + style="stop-color:#3c3c3c;stop-opacity:0;" /> + fx="-172.875" + cy="119.59179" + cx="-172.875" + gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,158.26577,1130.8958)" + gradientUnits="userSpaceOnUse" + id="radialGradient5639-0" + xlink:href="#linearGradient3715-2-4" + inkscape:collect="always" /> + id="stop3717-4-8" /> + id="stop3719-9-7" /> + fx="-182.4375" + cy="116.19179" + cx="-182.4375" + gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,218.94267,1272.3725)" + gradientUnits="userSpaceOnUse" + id="radialGradient5641-1" + xlink:href="#linearGradient5299-7" + inkscape:collect="always" /> + id="stop5301-2" /> + id="stop5303-7" /> - + - + + id="radialGradient5964" + cx="-103.70541" + cy="-39.275696" + fx="-103.70541" + fy="-39.275696" + r="20.15" + gradientTransform="matrix(0.61309318,1.698523,-1.2180273,0.43965501,-77.239822,152.43381)" + gradientUnits="userSpaceOnUse" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + y1="-45.656265" + x2="-72.843758" + y2="-45.944225" + gradientTransform="matrix(0.91762814,0,0,1.0003875,-5.0078269,1004.2961)" /> - + + + + id="radialGradient3865" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.00108712,0.18221846,-0.82985011,4.6460161e-7,-113.08325,972.23283)" + cx="-116.29909" + cy="-37.504356" + fx="-116.29909" + fy="-37.504356" + r="20" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="stop4678" /> + id="stop4680" /> + id="stop4693" /> + id="stop4695" /> + id="stop4715" /> + style="stop-color:#707070;stop-opacity:0;" /> + id="stop4717" /> + id="stop4725" /> + id="stop4727" /> + id="stop4655" /> + id="stop4657" /> - - - - - - - - - - - - - - - + y1="1139.3492" + x1="203.09436" + id="linearGradient9295" + xlink:href="#linearGradient9289" + inkscape:collect="always" /> + gradientUnits="userSpaceOnUse" + y2="1151.9221" + x2="127.51315" + y1="1154.9745" + x1="124.46073" + id="linearGradient9311" + xlink:href="#linearGradient9305" + inkscape:collect="always" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1270,90 +1528,61 @@ + inkscape:groupmode="layer" + inkscape:label="Livello 1"> + transform="matrix(0.29626046,0,0,0.29626046,-45.835699,695.27639)" + id="g8044"> - + transform="translate(1.4700294,-5.8981036)" + id="g9364"> - - - - - - - - + transform="translate(98.027824,-15.186023)" /> - - + id="path4273" + d="m 206.47648,1074.7314 55.59925,0 0,45.7242 -55.59925,10e-5 0,-45.7243" + style="fill:url(#linearGradient6171-857-364-729);fill-opacity:1;stroke:#303030;stroke-opacity:1;stroke-width:1.01262247;stroke-miterlimit:4;stroke-dasharray:none" /> + style="fill:#452500;fill-opacity:1;fill-rule:evenodd;stroke:#303030;stroke-width:0.83544666;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + id="path2415" + d="m 169.25185,1184.8538 130.00422,0 -37.18034,-64.3982 -55.59925,0 -37.22463,64.3982 z" + inkscape:connector-curvature="0" /> + + + + id="g9321" /> From e97319c0bba33b551861183a0d5f0d799f2b978f Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 23 Mar 2013 19:32:37 +0100 Subject: [PATCH 038/817] Drawer as container icon looks actually quite good IMHO. --- .../referenceable record type/container.svg | 183 +++++++++++++----- 1 file changed, 134 insertions(+), 49 deletions(-) diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg index 2a93954bd..6c4973708 100644 --- a/files/opencs/scalable/referenceable record type/container.svg +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -23,11 +23,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="8.0000004" - inkscape:cx="7.2255179" - inkscape:cy="2.9394873" + inkscape:zoom="5.6568545" + inkscape:cx="-6.640249" + inkscape:cy="16.907775" inkscape:document-units="px" - inkscape:current-layer="g9364" + inkscape:current-layer="g8044" showgrid="true" showguides="true" inkscape:guide-bbox="true" @@ -45,7 +45,7 @@ inkscape:object-paths="true" inkscape:snap-intersection-paths="true" inkscape:object-nodes="true" - inkscape:snap-global="true" + inkscape:snap-global="false" inkscape:snap-smooth-nodes="true" inkscape:snap-grids="false" inkscape:snap-nodes="true" @@ -72,6 +72,18 @@ + + + + @@ -1502,7 +1514,8 @@ x1="227.6591" id="linearGradient6171-857-364-729" xlink:href="#linearGradient6165-696-389-794" - inkscape:collect="always" /> + inkscape:collect="always" + gradientTransform="matrix(0.87072097,0,0,1.0005854,30.284126,-0.66139717)" /> + + + + + + + @@ -1536,49 +1620,50 @@ transform="matrix(0.29626046,0,0,0.29626046,-45.835699,695.27639)" id="g8044"> - - - - - - - - + transform="translate(99.497853,-21.084127)" + style="fill:#ff0000;fill-opacity:1;stroke:none" + id="g3951" /> + + + + + + + Date: Sat, 23 Mar 2013 19:53:10 +0100 Subject: [PATCH 039/817] Update the status icons. X as removed.svg and backgrounds for status icons stolen from oxygen emblems :P It gives clear look for it. --- files/opencs/scalable/status/added.svg | 60 +- files/opencs/scalable/status/modified.svg | 60 +- files/opencs/scalable/status/removed.svg | 1065 ++++++++++----------- 3 files changed, 617 insertions(+), 568 deletions(-) diff --git a/files/opencs/scalable/status/added.svg b/files/opencs/scalable/status/added.svg index a5767d23b..e0af57002 100644 --- a/files/opencs/scalable/status/added.svg +++ b/files/opencs/scalable/status/added.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2.8284271" - inkscape:cx="6.6635778" - inkscape:cy="31.541579" + inkscape:zoom="5.6568542" + inkscape:cx="27.462558" + inkscape:cy="10.232345" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -878,6 +878,29 @@ stdDeviation="57.354192" id="feGaussianBlur4632" /> + + + + + @@ -896,6 +919,35 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Livello 1"> + + + + + + + + + + + + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-linejoin:round" /> + + + + + @@ -1081,6 +1104,35 @@ + + + + + + + + + + + - - + inkscape:snap-nodes="true" /> + id="linearGradient3902" + inkscape:collect="always"> + + + + + + + + + + + + + + + + + - - + id="stop7491" /> - - - - + id="linearGradient6034"> + id="stop6036" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="stop6038" /> @@ -443,17 +343,6 @@ offset="1" id="stop3822" /> - - - - - - - + id="linearGradient3955-87-471"> + + + + + + + + + + - + gradientTransform="translate(-5.8907179,205.15612)" /> + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.60717495,0,6.6355278)" + r="3.1054714" + fy="16.891813" + fx="29.111721" + cy="16.891813" + cx="29.111721" + id="radialGradient3892" + xlink:href="#linearGradient3886" + inkscape:collect="always" /> + + + + - - - - - - - - - - - - + gradientTransform="translate(-183.1468,-158.28118)" /> + id="linearGradient3942"> + + + + gradientTransform="matrix(1,0,0,1.0000234,0,-0.00345228)" + cx="237.35278" + cy="147.22479" + fx="237.35278" + fy="147.22479" + r="107.16857" /> + + + + + gradientTransform="matrix(0.43641683,0,0,0.43645606,205.85223,33.676924)" + cx="72.191498" + cy="260.15875" + fx="72.191498" + fy="260.15875" + r="149.18433" /> + + + + + gradientTransform="matrix(1,0,0,1.0000234,0,-0.00611206)" + cx="83.637177" + cy="260.86032" + fx="83.637177" + fy="260.86032" + r="107.16857" /> + + + + + gradientTransform="matrix(0.43641683,0,0,0.43645606,52.136611,147.31246)" + cx="72.191498" + cy="260.15875" + fx="72.191498" + fy="260.15875" + r="149.18433" /> + + + + + gradientTransform="matrix(1,0,0,1.0000234,0,-0.00345228)" + cx="237.35278" + cy="147.22479" + fx="237.35278" + fy="147.22479" + r="107.16857" /> + + + + + gradientTransform="matrix(0.43641683,0,0,0.43645606,205.85223,33.676924)" + cx="72.191498" + cy="260.15875" + fx="72.191498" + fy="260.15875" + r="149.18433" /> + + + + - - - - + + + + + + gradientTransform="matrix(0.43641683,0,0,0.43645606,205.85223,33.676924)" + cx="72.191498" + cy="260.15875" + fx="72.191498" + fy="260.15875" + r="149.18433" /> + + + + + + + + + + + + + + + + + + + + + + - - - - - - + id="linearGradient3133-9"> + + + @@ -989,36 +920,50 @@ inkscape:groupmode="layer" inkscape:label="Livello 1"> + id="g6138" + transform="translate(3.5529905,1004.1857)"> - - - + transform="matrix(3.2000002,0,0,3.2000002,101.31818,-39.364891)" + id="g6116"> + + + + + + + + + + From b7f95cd271b522f28d4dcf86799648ecd43e785f Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 24 Mar 2013 10:19:46 +0100 Subject: [PATCH 040/817] Random item (dice). Container.svg needs to be scraped, I'm afraid. --- .../referenceable record type/container.svg | 2770 +++++++++-------- .../referenceable record type/potion.svg | 107 +- .../referenceable record type/random item.svg | 1462 +++++++++ 3 files changed, 3045 insertions(+), 1294 deletions(-) create mode 100644 files/opencs/scalable/referenceable record type/random item.svg diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg index 6c4973708..8c9465b66 100644 --- a/files/opencs/scalable/referenceable record type/container.svg +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -23,11 +23,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="5.6568545" - inkscape:cx="-6.640249" - inkscape:cy="16.907775" + inkscape:zoom="11.313709" + inkscape:cx="13.572484" + inkscape:cy="13.658831" inkscape:document-units="px" - inkscape:current-layer="g8044" + inkscape:current-layer="g3302" showgrid="true" showguides="true" inkscape:guide-bbox="true" @@ -51,1553 +51,1721 @@ inkscape:snap-nodes="true" inkscape:snap-midpoints="false"> + id="grid3225" + type="xygrid" /> + id="guide5067" /> + id="guide5069" /> + id="guide5071" /> + id="guide5073" /> + id="linearGradient4932"> + style="stop-color:#000e50;stop-opacity:1;" /> + style="stop-color:#000e50;stop-opacity:0;" /> + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="linearGradient4853"> + style="stop-color:#eeeeee;stop-opacity:1;" /> + style="stop-color:#e1fbfa;stop-opacity:1;" /> + id="linearGradient4843"> + style="stop-color:#dcfaf9;stop-opacity:1;" /> + + style="stop-color:#dcfaf9;stop-opacity:1;" /> + id="linearGradient4817"> + style="stop-color:#caf8f6;stop-opacity:1;" /> + + style="stop-color:#caf8f6;stop-opacity:1;" /> + id="linearGradient4801"> + style="stop-color:#c8c8c8;stop-opacity:1;" /> + id="linearGradient4729"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="stop5027" /> + + id="stop5029" /> + + + + + + + + + + + + + + + + + + + + + + + + + style="stop-color:#000000;stop-opacity:0;" /> + style="stop-color:#000000;stop-opacity:1;" /> + id="linearGradient3882" + inkscape:collect="always"> + style="stop-color:#000000;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:0;" /> + style="stop-color:#000000;stop-opacity:0.784" /> + style="stop-color:#000000;stop-opacity:0;" /> + style="stop-color:#ffffff;stop-opacity:0.78431374;" /> + style="stop-color:#b4b4b4;stop-opacity:0.72549021;" /> + style="stop-color:#5a0048;stop-opacity:1;" /> + style="stop-color:#960078;stop-opacity:1;" /> + style="stop-color:#caf8f6;stop-opacity:0.39215687;" /> + id="stop3861" /> + style="stop-color:#caf8f6;stop-opacity:0.39215687;" /> + style="stop-color:#aa0088;stop-opacity:1;" /> + style="stop-color:#fa00c8;stop-opacity:1;" /> + style="stop-color:#ffffff;stop-opacity:0.78431374;" /> + style="stop-color:#caf8f6;stop-opacity:0;" /> + id="linearGradient5958" + inkscape:collect="always"> + style="stop-color:#caf8f6;stop-opacity:1;" /> + style="stop-color:#caf8f6;stop-opacity:0;" /> + style="stop-color:#c84900;stop-opacity:1;" /> + style="stop-color:#c84900;stop-opacity:0.19607843;" /> + id="stop6817" /> + style="stop-color:#3c3c3c;stop-opacity:0.58823532;" /> + id="stop6819" /> + id="stop4024" /> + id="stop4026" /> + id="stop3725" /> + id="stop3727" /> + id="stop3717" /> + id="stop3719" /> + id="stop3709" /> + id="stop3711" /> - + - - - - - - - - - - - - - + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + gradientTransform="translate(0.2341189,5.74082)" /> + + + + + + + + + + + + + + style="stop-color:#1e1e1e;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:0;" /> + id="radialGradient5639" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.23290796,0.98292589,-1.5211573,0.36044393,244.44953,1091.8596)" + cx="-171.01654" + cy="123.88583" + fx="-171.01654" + fy="123.88583" + r="29.000444" /> + style="stop-color:#ffffff;stop-opacity:1;" /> + style="stop-color:#b3bbad;stop-opacity:1;" /> + id="radialGradient5641" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,227.36718,1219.3395)" + cx="-182.4375" + cy="116.19179" + fx="-182.4375" + fy="116.19179" + r="28.421875" /> + style="stop-color:#000e50;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:1;" /> - + xlink:href="#linearGradient3715-2" + id="radialGradient6812" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,240.54684,45.0811)" + cx="-172.875" + cy="119.59179" + fx="-172.875" + fy="119.59179" + r="29.000444" /> + + + + + + - - - - - + + y1="941.44623" + x1="63.765881" + gradientTransform="matrix(-0.28231332,0,0,0.28231332,64.982195,664.15172)" + gradientUnits="userSpaceOnUse" + id="linearGradient3321" + xlink:href="#linearGradient3715-6" + inkscape:collect="always" /> - + id="linearGradient6823-6" + x1="27.183681" + y1="39.630547" + x2="26.643335" + y2="37.613949" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-82.281067,1085.8147)" /> + id="stop6817-4" /> + style="stop-color:#3c3c3c;stop-opacity:0.58823532;" /> + id="stop6819-5" /> + id="radialGradient5639-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,158.26577,1130.8958)" + cx="-172.875" + cy="119.59179" + fx="-172.875" + fy="119.59179" + r="29.000444" /> + style="stop-color:#ffffff;stop-opacity:1;" /> + style="stop-color:#b3bbad;stop-opacity:1;" /> + id="radialGradient5641-1" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,218.94267,1272.3725)" + cx="-182.4375" + cy="116.19179" + fx="-182.4375" + fy="116.19179" + r="28.421875" /> + style="stop-color:#000e50;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:1;" /> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="linearGradient5973" + xlink:href="#linearGradient5922" + inkscape:collect="always" /> + fx="-97.089668" + cy="-33.913769" + cx="-97.089668" + id="radialGradient3843" + xlink:href="#linearGradient3837" + inkscape:collect="always" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + style="stop-color:#d07200;stop-opacity:1;" /> + style="stop-color:#603500;stop-opacity:1;" /> + style="stop-color:#ffffff;stop-opacity:1;" /> + style="stop-color:#cccccc;stop-opacity:0;" /> + style="stop-color:#000000;stop-opacity:1" /> + id="stop4721" /> + style="stop-color:#000000;stop-opacity:1;" /> + style="stop-color:#969696;stop-opacity:1;" /> + style="stop-color:#cccccc;stop-opacity:1;" /> + style="stop-color:#fa00c8;stop-opacity:1;" /> + style="stop-color:#aa0088;stop-opacity:1;" /> - + - - - - - - + y1="1154.9745" + x2="127.51315" + y2="1151.9221" + gradientUnits="userSpaceOnUse" /> - - + + + + + + + + + id="linearGradient6042" + gradientUnits="userSpaceOnUse" + x1="-2256.6802" + y1="1067.036" + x2="37.487514" + y2="2532.4438" + gradientTransform="translate(-1.6900304,-354.84909)" /> + id="stop6036" /> + id="stop6038" /> - + - + - + - + - + + id="linearGradient5095" + x1="5.8733373" + y1="28.879158" + x2="15.974848" + y2="24.861507" + gradientUnits="userSpaceOnUse" /> + id="linearGradient5105" + x1="44.388447" + y1="29.089437" + x2="34.262527" + y2="24.798422" + gradientUnits="userSpaceOnUse" /> + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + inkscape:collect="always" /> + y2="68.443649" + x2="148.13901" + y1="101.13522" + x1="135.41849" + id="linearGradient4807" + xlink:href="#linearGradient4801" + inkscape:collect="always" /> + + + + + + + + + + + + + @@ -1612,62 +1780,120 @@ + id="layer1" + transform="translate(0,-1004.3622)"> + id="g8044" + transform="matrix(0.29626046,0,0,0.29626046,-45.835699,695.27639)"> - - - - - - - + transform="translate(99.497853,-21.084127)" /> + transform="translate(156.56239,-59.761743)" /> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg index 612f45aa4..552c14f19 100644 --- a/files/opencs/scalable/referenceable record type/potion.svg +++ b/files/opencs/scalable/referenceable record type/potion.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="7.2407734" - inkscape:cx="3.6117613" - inkscape:cy="14.120537" + inkscape:zoom="5.12" + inkscape:cx="-13.774317" + inkscape:cy="16.062941" inkscape:document-units="px" inkscape:current-layer="g3910" showgrid="true" @@ -41,7 +41,7 @@ inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-bbox-midpoints="true" + inkscape:snap-bbox-midpoints="false" inkscape:object-paths="true" inkscape:snap-intersection-paths="false" inkscape:object-nodes="false" @@ -55,6 +55,21 @@ + + + + + + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.2031694,0,0,1.0551213,-87.506267,947.79452)" /> + + + + + @@ -1067,26 +1130,26 @@ d="m -133.13494,-22.158251 c 0,2.440777 -8.84205,4.419418 -19.74928,4.419418 -10.90722,0 -19.74927,-1.978641 -19.74927,-4.419418 0,-2.440777 8.84205,-4.419417 19.74927,-4.419417 10.90723,0 19.74928,1.97864 19.74928,4.419417 z" transform="matrix(0.33492065,0,0,0.3605492,-27.223425,956.85737)" /> + style="opacity:0.75;fill:url(#linearGradient3148);fill-opacity:1;stroke:#7d7d7d;stroke-width:0.43104154;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m -84.982974,948.64215 c -0.64997,0.0595 -1.165571,0.65963 -1.165571,1.38485 l 0,2.6378 c 0,0.7229 0.518091,1.32155 1.165571,1.38485 l 0,0.46162 c 0.544843,-0.74781 3.244284,-1.3189 6.504634,-1.3189 3.36081,0 6.119682,0.60297 6.542234,1.38484 l 0.0752,0 0,-0.52756 c 0.64747,-0.063 1.16557,-0.66195 1.16557,-1.38485 l 0,-2.6378 c 0,-0.73861 -0.535775,-1.34418 -1.203169,-1.38485 0.04468,0.0748 0.0752,0.15305 0.0752,0.23081 0,0.88002 -2.964378,1.58268 -6.617432,1.58268 -3.653054,0 -6.617431,-0.70266 -6.617431,-1.58268 0,-0.076 0.03245,-0.15762 0.0752,-0.23081 z" + id="path3920" + inkscape:connector-curvature="0" /> + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + From 37a1fb6b7c82a5477c17faf6ec8538e0e2a03676 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 26 Mar 2013 09:41:26 +0100 Subject: [PATCH 041/817] Adding ingredient.svg icon. I need to work on random-item and scrap container icon. --- .../referenceable record type/ingredient.svg | 1112 ++++++++++ .../referenceable record type/light.svg | 1513 +++++++++++++ .../referenceable record type/random-item.svg | 1462 +++++++++++++ .../scalable/referenceable-record/.directory | 5 + .../referenceable-record/activator.svg | 1088 ++++++++++ .../referenceable-record/apparatus.svg | 1058 +++++++++ .../scalable/referenceable-record/book.svg | 692 ++++++ .../referenceable-record/container.svg | 1899 +++++++++++++++++ .../referenceable-record/ingredient.svg | 1112 ++++++++++ .../scalable/referenceable-record/light.svg | 1513 +++++++++++++ .../scalable/referenceable-record/potion.svg | 1161 ++++++++++ .../referenceable-record/random-item.svg | 1462 +++++++++++++ .../scalable/referenceable-record/repair.svg | 1280 +++++++++++ .../scalable/referenceable-record/static.svg | 1141 ++++++++++ .../scalable/referenceable-record/weapon.svg | 1206 +++++++++++ 15 files changed, 17704 insertions(+) create mode 100644 files/opencs/scalable/referenceable record type/ingredient.svg create mode 100644 files/opencs/scalable/referenceable record type/light.svg create mode 100644 files/opencs/scalable/referenceable record type/random-item.svg create mode 100644 files/opencs/scalable/referenceable-record/.directory create mode 100644 files/opencs/scalable/referenceable-record/activator.svg create mode 100644 files/opencs/scalable/referenceable-record/apparatus.svg create mode 100644 files/opencs/scalable/referenceable-record/book.svg create mode 100644 files/opencs/scalable/referenceable-record/container.svg create mode 100644 files/opencs/scalable/referenceable-record/ingredient.svg create mode 100644 files/opencs/scalable/referenceable-record/light.svg create mode 100644 files/opencs/scalable/referenceable-record/potion.svg create mode 100644 files/opencs/scalable/referenceable-record/random-item.svg create mode 100644 files/opencs/scalable/referenceable-record/repair.svg create mode 100644 files/opencs/scalable/referenceable-record/static.svg create mode 100644 files/opencs/scalable/referenceable-record/weapon.svg diff --git a/files/opencs/scalable/referenceable record type/ingredient.svg b/files/opencs/scalable/referenceable record type/ingredient.svg new file mode 100644 index 000000000..a77a9c8ee --- /dev/null +++ b/files/opencs/scalable/referenceable record type/ingredient.svg @@ -0,0 +1,1112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/light.svg b/files/opencs/scalable/referenceable record type/light.svg new file mode 100644 index 000000000..f8f506636 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/light.svg @@ -0,0 +1,1513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/random-item.svg b/files/opencs/scalable/referenceable record type/random-item.svg new file mode 100644 index 000000000..0c132ce95 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/random-item.svg @@ -0,0 +1,1462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory new file mode 100644 index 000000000..e2d80ed58 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/referenceable-record/activator.svg b/files/opencs/scalable/referenceable-record/activator.svg new file mode 100644 index 000000000..0c6db59a7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/activator.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/apparatus.svg b/files/opencs/scalable/referenceable-record/apparatus.svg new file mode 100644 index 000000000..37cef0e89 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/apparatus.svg @@ -0,0 +1,1058 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/book.svg b/files/opencs/scalable/referenceable-record/book.svg new file mode 100644 index 000000000..8c041a9e7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/book.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/container.svg b/files/opencs/scalable/referenceable-record/container.svg new file mode 100644 index 000000000..8c9465b66 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/container.svg @@ -0,0 +1,1899 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/ingredient.svg b/files/opencs/scalable/referenceable-record/ingredient.svg new file mode 100644 index 000000000..a77a9c8ee --- /dev/null +++ b/files/opencs/scalable/referenceable-record/ingredient.svg @@ -0,0 +1,1112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/light.svg b/files/opencs/scalable/referenceable-record/light.svg new file mode 100644 index 000000000..f8f506636 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/light.svg @@ -0,0 +1,1513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/potion.svg b/files/opencs/scalable/referenceable-record/potion.svg new file mode 100644 index 000000000..552c14f19 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/potion.svg @@ -0,0 +1,1161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/random-item.svg b/files/opencs/scalable/referenceable-record/random-item.svg new file mode 100644 index 000000000..0c132ce95 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/random-item.svg @@ -0,0 +1,1462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/repair.svg b/files/opencs/scalable/referenceable-record/repair.svg new file mode 100644 index 000000000..b1a23956e --- /dev/null +++ b/files/opencs/scalable/referenceable-record/repair.svg @@ -0,0 +1,1280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/static.svg b/files/opencs/scalable/referenceable-record/static.svg new file mode 100644 index 000000000..a6f29370f --- /dev/null +++ b/files/opencs/scalable/referenceable-record/static.svg @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/weapon.svg b/files/opencs/scalable/referenceable-record/weapon.svg new file mode 100644 index 000000000..2e832fff7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/weapon.svg @@ -0,0 +1,1206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + From cf0c55b37fa033ab6748ffa814a6c89bddf7c543 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 26 Mar 2013 10:28:43 +0100 Subject: [PATCH 042/817] New random-item. Looks a lot better. --- .../referenceable-record/random-item.svg | 1560 ++--------------- 1 file changed, 127 insertions(+), 1433 deletions(-) diff --git a/files/opencs/scalable/referenceable-record/random-item.svg b/files/opencs/scalable/referenceable-record/random-item.svg index 0c132ce95..d051ce049 100644 --- a/files/opencs/scalable/referenceable-record/random-item.svg +++ b/files/opencs/scalable/referenceable-record/random-item.svg @@ -1,5 +1,5 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + inkscape:version="0.48.4 r9939" + sodipodi:docname="random-item.svg"> + id="metadata14614"> image/svg+xml - + + + + id="layer1"> + transform="translate(26.2199, 33.6274)" + fill="#fa0000" + d="M6.67184 0L6.67184 3.5776L0 3.5776L10.8901 14.3726L21.7801 3.5776L15.1083 3.5776L15.1083 0Z" /> - - - - - - - - - + transform="translate(-0.222381, -0.133277)" + fill="none"> + + + + + + + + + + + + + + + + + From efe6a3ebeec495a213a75ed3c072d9d2eb1c8c95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Mar 2013 18:01:01 +0100 Subject: [PATCH 043/817] Fix compile error & warnings --- apps/openmw/mwmechanics/aitravel.cpp | 6 +-- apps/openmw/mwmechanics/aitravel.hpp | 60 ++++++++++++++-------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 94f6fd892..2c5260a62 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -46,7 +46,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; - for(int i=1; imPoints.size();i++) + for(unsigned int i=1; imPoints.size();++i) { if(distance(grid->mPoints[i],x,y,z)mPoints.size();i++) + for(unsigned int i = 0;imPoints.size();++i) { PointID pID = boost::add_vertex(graph); graph[pID].mX = pathgrid->mPoints[i].mX + xCell; @@ -147,7 +147,7 @@ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCe graph[pID].mZ = pathgrid->mPoints[i].mZ; } - for(int i = 0;imEdges.size();i++) + for(unsigned int i = 0;imEdges.size();++i) { PointID u = pathgrid->mEdges[i].mV0; PointID v = pathgrid->mEdges[i].mV1; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 3d220cb7e..ef2359ba9 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,35 +1,35 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H - -#include "aipackage.hpp" -#include "components\esm\loadpgrd.hpp" -#include - -namespace MWMechanics -{ - class AiTravel : public AiPackage - { - public: - AiTravel(float x, float y, float z); - virtual AiTravel *clone() const; - - virtual bool execute (const MWWorld::Ptr& actor); - ///< \return Package completed? - - virtual int getTypeId() const; - - private: - float mX; - float mY; - float mZ; - - int cellX; - int cellY; - - bool isPathConstructed; - std::list mPath; - - }; + +#include "aipackage.hpp" +#include +#include + +namespace MWMechanics +{ + class AiTravel : public AiPackage + { + public: + AiTravel(float x, float y, float z); + virtual AiTravel *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + float mX; + float mY; + float mZ; + + int cellX; + int cellY; + + bool isPathConstructed; + std::list mPath; + + }; } #endif From 623f9c2a587d1bdeb836c0acbd2c029e651dbbde Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 27 Mar 2013 19:52:12 +0100 Subject: [PATCH 044/817] A new icon for misc iteams. I really hope that scales will do. --- .../referenceable-record/miscelanius.svg | 965 ++++++++++++++++++ .../referenceable-record/miscellaneous.svg | 692 +++++++++++++ 2 files changed, 1657 insertions(+) create mode 100644 files/opencs/scalable/referenceable-record/miscelanius.svg create mode 100644 files/opencs/scalable/referenceable-record/miscellaneous.svg diff --git a/files/opencs/scalable/referenceable-record/miscelanius.svg b/files/opencs/scalable/referenceable-record/miscelanius.svg new file mode 100644 index 000000000..96522048c --- /dev/null +++ b/files/opencs/scalable/referenceable-record/miscelanius.svg @@ -0,0 +1,965 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/miscellaneous.svg b/files/opencs/scalable/referenceable-record/miscellaneous.svg new file mode 100644 index 000000000..8c041a9e7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/miscellaneous.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + From 7dbc779c3aa4b40e4efabe918cc285c587b5d522 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sat, 30 Mar 2013 19:08:42 +0100 Subject: [PATCH 045/817] Self-enchanting mechanics --- apps/openmw/mwgui/enchantingdialog.cpp | 22 +++++++++-- apps/openmw/mwmechanics/enchanting.cpp | 55 ++++++++++++++++++++++++-- apps/openmw/mwmechanics/enchanting.hpp | 9 ++++- 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index ef124bb43..7d5d1411f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -19,7 +19,6 @@ namespace MWGui : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) , EffectEditorBase(parWindowManager) , mItemSelectionDialog(NULL) - , mEnchanting(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) { getWidget(mName, "NameEdit"); getWidget(mCancelButton, "CancelButton"); @@ -87,6 +86,9 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(actor); + mPtr = actor; startEditing (); @@ -94,7 +96,14 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { - /// \todo + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + mEnchanting.setSelfEnchanting(true); + mEnchanting.setEnchanter(player); + + mPtr = player; + + startEditing(); } void EnchantingDialog::onReferenceUnavailable () @@ -264,8 +273,13 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - mEnchanting.create(); - mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + int result = mEnchanting.create(); + + if(result==1) + mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + else + mWindowManager.messageBox ("#{sNotifyMessage34}"); + mWindowManager.removeGuiMode (GM_Enchanting); } } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 4ef20a5e5..3590ae0f3 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -3,10 +3,13 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" + +#include "creaturestats.hpp" +#include "npcstats.hpp" + namespace MWMechanics { - Enchanting::Enchanting(MWWorld::Ptr enchanter): - mEnchanter(enchanter), + Enchanting::Enchanting(): mEnchantType(0) {} @@ -45,11 +48,20 @@ namespace MWMechanics mSoulGemPtr=soulGem; } - void Enchanting::create() + int Enchanting::create() { - mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + if(mSelfEnchanting) + { + if(getEnchantChance() (RAND_MAX)*100) + return 0; + + MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); + } + + mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); + mEnchantment.mData.mCharge = getGemCharge(); if(mEnchantType==3) { @@ -67,6 +79,7 @@ namespace MWMechanics MWWorld::Ptr result = mOldItemPtr; result.mPtr = newobjPtr.mPtr; MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (result); + return 1; } void Enchanting::nextEnchantType() @@ -110,6 +123,10 @@ namespace MWMechanics float cost = 0; std::vector mEffects = mEffectList.mList; int i=mEffects.size(); + + /* + Formula from http://www.uesp.net/wiki/Morrowind:Enchant + */ for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { const ESM::MagicEffect* effect = store.get().find(it->mEffectID); @@ -164,4 +181,34 @@ namespace MWMechanics return true; return false; } + + void Enchanting::setSelfEnchanting(bool selfEnchanting) + { + mSelfEnchanting = selfEnchanting; + } + + void Enchanting::setEnchanter(MWWorld::Ptr enchanter) + { + mEnchanter = enchanter; + } + + float Enchanting::getEnchantChance() + { + /* + Formula from http://www.uesp.net/wiki/Morrowind:Enchant + */ + const CreatureStats& creatureStats = MWWorld::Class::get (mEnchanter).getCreatureStats (mEnchanter); + const NpcStats& npcStats = MWWorld::Class::get (mEnchanter).getNpcStats (mEnchanter); + + float chance1 = (npcStats.getSkill (ESM::Skill::Enchant).getModified() + + (0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified()) + + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); + + float chance2 = 2.5 * getEnchantCost(); + if(mEnchantType==3) + { + chance2 *= 2; + } + return (chance1-chance2); + } } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 1daf34c6d..fffa2c5b2 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -16,6 +16,8 @@ namespace MWMechanics const MWWorld::Ptr *mNewItemPtr; int mEnchantType; + bool mSelfEnchanting; + ESM::EffectList mEffectList; ESM::Enchantment mEnchantment; @@ -23,17 +25,20 @@ namespace MWMechanics std::string mObjectType; std::string mOldItemId; public: - Enchanting(MWWorld::Ptr enchanter); + Enchanting(); + void setEnchanter(MWWorld::Ptr enchanter); + void setSelfEnchanting(bool selfEnchanting); void setOldItem(MWWorld::Ptr oldItem); void setNewItemName(std::string s); void setEffect(ESM::EffectList effectList); void setSoulGem(MWWorld::Ptr soulGem); - void create(); + int create(); void nextEnchantType(); int getEnchantType(); int getEnchantCost(); int getMaxEnchantValue(); int getGemCharge(); + float getEnchantChance(); bool soulEmpty(); bool itemEmpty(); }; From faf293bd6d1f28827a6209fd63f63cba5d5aec29 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 31 Mar 2013 09:50:35 +0200 Subject: [PATCH 046/817] Removing old directory. --- files/opencs/scalable/Palette.svg | 569 ----- .../referenceable record type/.directory | 5 - .../referenceable record type/activator.svg | 1088 ---------- .../referenceable record type/apparatus.svg | 1058 --------- .../referenceable record type/book.svg | 692 ------ .../referenceable record type/container.svg | 1899 ----------------- .../referenceable record type/ingredient.svg | 1112 ---------- .../light source.svg | 1513 ------------- .../referenceable record type/light.svg | 1513 ------------- .../referenceable record type/potion.svg | 1161 ---------- .../referenceable record type/random item.svg | 1462 ------------- .../referenceable record type/random-item.svg | 1462 ------------- .../referenceable record type/repair.svg | 1280 ----------- .../referenceable record type/static.svg | 1141 ---------- .../referenceable record type/weapon.svg | 1206 ----------- .../scalable/referenceable-record/.directory | 5 - .../referenceable-record/activator.svg | 1088 ---------- .../referenceable-record/apparatus.svg | 1058 --------- .../scalable/referenceable-record/book.svg | 692 ------ .../referenceable-record/container.svg | 1899 ----------------- .../referenceable-record/ingredient.svg | 1112 ---------- .../scalable/referenceable-record/light.svg | 1513 ------------- .../referenceable-record/miscelanius.svg | 965 --------- .../referenceable-record/miscellaneous.svg | 692 ------ .../scalable/referenceable-record/potion.svg | 1161 ---------- .../referenceable-record/random-item.svg | 156 -- .../scalable/referenceable-record/repair.svg | 1280 ----------- .../scalable/referenceable-record/static.svg | 1141 ---------- .../scalable/referenceable-record/weapon.svg | 1206 ----------- files/opencs/scalable/status/.directory | 5 - files/opencs/scalable/status/added.svg | 969 --------- files/opencs/scalable/status/modified.svg | 1192 ----------- files/opencs/scalable/status/removed.svg | 969 --------- 33 files changed, 34264 deletions(-) delete mode 100644 files/opencs/scalable/Palette.svg delete mode 100644 files/opencs/scalable/referenceable record type/.directory delete mode 100644 files/opencs/scalable/referenceable record type/activator.svg delete mode 100644 files/opencs/scalable/referenceable record type/apparatus.svg delete mode 100644 files/opencs/scalable/referenceable record type/book.svg delete mode 100644 files/opencs/scalable/referenceable record type/container.svg delete mode 100644 files/opencs/scalable/referenceable record type/ingredient.svg delete mode 100644 files/opencs/scalable/referenceable record type/light source.svg delete mode 100644 files/opencs/scalable/referenceable record type/light.svg delete mode 100644 files/opencs/scalable/referenceable record type/potion.svg delete mode 100644 files/opencs/scalable/referenceable record type/random item.svg delete mode 100644 files/opencs/scalable/referenceable record type/random-item.svg delete mode 100644 files/opencs/scalable/referenceable record type/repair.svg delete mode 100644 files/opencs/scalable/referenceable record type/static.svg delete mode 100644 files/opencs/scalable/referenceable record type/weapon.svg delete mode 100644 files/opencs/scalable/referenceable-record/.directory delete mode 100644 files/opencs/scalable/referenceable-record/activator.svg delete mode 100644 files/opencs/scalable/referenceable-record/apparatus.svg delete mode 100644 files/opencs/scalable/referenceable-record/book.svg delete mode 100644 files/opencs/scalable/referenceable-record/container.svg delete mode 100644 files/opencs/scalable/referenceable-record/ingredient.svg delete mode 100644 files/opencs/scalable/referenceable-record/light.svg delete mode 100644 files/opencs/scalable/referenceable-record/miscelanius.svg delete mode 100644 files/opencs/scalable/referenceable-record/miscellaneous.svg delete mode 100644 files/opencs/scalable/referenceable-record/potion.svg delete mode 100644 files/opencs/scalable/referenceable-record/random-item.svg delete mode 100644 files/opencs/scalable/referenceable-record/repair.svg delete mode 100644 files/opencs/scalable/referenceable-record/static.svg delete mode 100644 files/opencs/scalable/referenceable-record/weapon.svg delete mode 100644 files/opencs/scalable/status/.directory delete mode 100644 files/opencs/scalable/status/added.svg delete mode 100644 files/opencs/scalable/status/modified.svg delete mode 100644 files/opencs/scalable/status/removed.svg diff --git a/files/opencs/scalable/Palette.svg b/files/opencs/scalable/Palette.svg deleted file mode 100644 index f42475330..000000000 --- a/files/opencs/scalable/Palette.svg +++ /dev/null @@ -1,569 +0,0 @@ - - - - - - - image/svg+xml - - - - - - Tango Palette - - - Tuomas Kuosmanen - - - - - Garrett Le Sage -Kenneth Wimer -Jakub Steiner - - -http://www.tango-project.org/files/Tango-Palette.svg - - - unify - global - theme - color - palette - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/files/opencs/scalable/referenceable record type/.directory b/files/opencs/scalable/referenceable record type/.directory deleted file mode 100644 index e2d80ed58..000000000 --- a/files/opencs/scalable/referenceable record type/.directory +++ /dev/null @@ -1,5 +0,0 @@ -[Dolphin] -PreviewsShown=true -Timestamp=2013,3,21,10,19,49 -Version=3 -ViewMode=1 diff --git a/files/opencs/scalable/referenceable record type/activator.svg b/files/opencs/scalable/referenceable record type/activator.svg deleted file mode 100644 index 0c6db59a7..000000000 --- a/files/opencs/scalable/referenceable record type/activator.svg +++ /dev/null @@ -1,1088 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/apparatus.svg b/files/opencs/scalable/referenceable record type/apparatus.svg deleted file mode 100644 index 37cef0e89..000000000 --- a/files/opencs/scalable/referenceable record type/apparatus.svg +++ /dev/null @@ -1,1058 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/book.svg b/files/opencs/scalable/referenceable record type/book.svg deleted file mode 100644 index 8c041a9e7..000000000 --- a/files/opencs/scalable/referenceable record type/book.svg +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg deleted file mode 100644 index 8c9465b66..000000000 --- a/files/opencs/scalable/referenceable record type/container.svg +++ /dev/null @@ -1,1899 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/ingredient.svg b/files/opencs/scalable/referenceable record type/ingredient.svg deleted file mode 100644 index a77a9c8ee..000000000 --- a/files/opencs/scalable/referenceable record type/ingredient.svg +++ /dev/null @@ -1,1112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/light source.svg b/files/opencs/scalable/referenceable record type/light source.svg deleted file mode 100644 index f8f506636..000000000 --- a/files/opencs/scalable/referenceable record type/light source.svg +++ /dev/null @@ -1,1513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/light.svg b/files/opencs/scalable/referenceable record type/light.svg deleted file mode 100644 index f8f506636..000000000 --- a/files/opencs/scalable/referenceable record type/light.svg +++ /dev/null @@ -1,1513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg deleted file mode 100644 index 552c14f19..000000000 --- a/files/opencs/scalable/referenceable record type/potion.svg +++ /dev/null @@ -1,1161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/random item.svg b/files/opencs/scalable/referenceable record type/random item.svg deleted file mode 100644 index 0c132ce95..000000000 --- a/files/opencs/scalable/referenceable record type/random item.svg +++ /dev/null @@ -1,1462 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/random-item.svg b/files/opencs/scalable/referenceable record type/random-item.svg deleted file mode 100644 index 0c132ce95..000000000 --- a/files/opencs/scalable/referenceable record type/random-item.svg +++ /dev/null @@ -1,1462 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/repair.svg b/files/opencs/scalable/referenceable record type/repair.svg deleted file mode 100644 index b1a23956e..000000000 --- a/files/opencs/scalable/referenceable record type/repair.svg +++ /dev/null @@ -1,1280 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/static.svg b/files/opencs/scalable/referenceable record type/static.svg deleted file mode 100644 index a6f29370f..000000000 --- a/files/opencs/scalable/referenceable record type/static.svg +++ /dev/null @@ -1,1141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/weapon.svg b/files/opencs/scalable/referenceable record type/weapon.svg deleted file mode 100644 index 2e832fff7..000000000 --- a/files/opencs/scalable/referenceable record type/weapon.svg +++ /dev/null @@ -1,1206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory deleted file mode 100644 index e2d80ed58..000000000 --- a/files/opencs/scalable/referenceable-record/.directory +++ /dev/null @@ -1,5 +0,0 @@ -[Dolphin] -PreviewsShown=true -Timestamp=2013,3,21,10,19,49 -Version=3 -ViewMode=1 diff --git a/files/opencs/scalable/referenceable-record/activator.svg b/files/opencs/scalable/referenceable-record/activator.svg deleted file mode 100644 index 0c6db59a7..000000000 --- a/files/opencs/scalable/referenceable-record/activator.svg +++ /dev/null @@ -1,1088 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/apparatus.svg b/files/opencs/scalable/referenceable-record/apparatus.svg deleted file mode 100644 index 37cef0e89..000000000 --- a/files/opencs/scalable/referenceable-record/apparatus.svg +++ /dev/null @@ -1,1058 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/book.svg b/files/opencs/scalable/referenceable-record/book.svg deleted file mode 100644 index 8c041a9e7..000000000 --- a/files/opencs/scalable/referenceable-record/book.svg +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/container.svg b/files/opencs/scalable/referenceable-record/container.svg deleted file mode 100644 index 8c9465b66..000000000 --- a/files/opencs/scalable/referenceable-record/container.svg +++ /dev/null @@ -1,1899 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/ingredient.svg b/files/opencs/scalable/referenceable-record/ingredient.svg deleted file mode 100644 index a77a9c8ee..000000000 --- a/files/opencs/scalable/referenceable-record/ingredient.svg +++ /dev/null @@ -1,1112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/light.svg b/files/opencs/scalable/referenceable-record/light.svg deleted file mode 100644 index f8f506636..000000000 --- a/files/opencs/scalable/referenceable-record/light.svg +++ /dev/null @@ -1,1513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/miscelanius.svg b/files/opencs/scalable/referenceable-record/miscelanius.svg deleted file mode 100644 index 96522048c..000000000 --- a/files/opencs/scalable/referenceable-record/miscelanius.svg +++ /dev/null @@ -1,965 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/miscellaneous.svg b/files/opencs/scalable/referenceable-record/miscellaneous.svg deleted file mode 100644 index 8c041a9e7..000000000 --- a/files/opencs/scalable/referenceable-record/miscellaneous.svg +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/potion.svg b/files/opencs/scalable/referenceable-record/potion.svg deleted file mode 100644 index 552c14f19..000000000 --- a/files/opencs/scalable/referenceable-record/potion.svg +++ /dev/null @@ -1,1161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/random-item.svg b/files/opencs/scalable/referenceable-record/random-item.svg deleted file mode 100644 index d051ce049..000000000 --- a/files/opencs/scalable/referenceable-record/random-item.svg +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/repair.svg b/files/opencs/scalable/referenceable-record/repair.svg deleted file mode 100644 index b1a23956e..000000000 --- a/files/opencs/scalable/referenceable-record/repair.svg +++ /dev/null @@ -1,1280 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/static.svg b/files/opencs/scalable/referenceable-record/static.svg deleted file mode 100644 index a6f29370f..000000000 --- a/files/opencs/scalable/referenceable-record/static.svg +++ /dev/null @@ -1,1141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/weapon.svg b/files/opencs/scalable/referenceable-record/weapon.svg deleted file mode 100644 index 2e832fff7..000000000 --- a/files/opencs/scalable/referenceable-record/weapon.svg +++ /dev/null @@ -1,1206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/status/.directory b/files/opencs/scalable/status/.directory deleted file mode 100644 index e2d80ed58..000000000 --- a/files/opencs/scalable/status/.directory +++ /dev/null @@ -1,5 +0,0 @@ -[Dolphin] -PreviewsShown=true -Timestamp=2013,3,21,10,19,49 -Version=3 -ViewMode=1 diff --git a/files/opencs/scalable/status/added.svg b/files/opencs/scalable/status/added.svg deleted file mode 100644 index e0af57002..000000000 --- a/files/opencs/scalable/status/added.svg +++ /dev/null @@ -1,969 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/status/modified.svg b/files/opencs/scalable/status/modified.svg deleted file mode 100644 index e278ce596..000000000 --- a/files/opencs/scalable/status/modified.svg +++ /dev/null @@ -1,1192 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/status/removed.svg b/files/opencs/scalable/status/removed.svg deleted file mode 100644 index 17719cfc8..000000000 --- a/files/opencs/scalable/status/removed.svg +++ /dev/null @@ -1,969 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - From 49b5b90cd55ecaf86945e2db0c23dc5a4f07056f Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 31 Mar 2013 10:13:01 +0200 Subject: [PATCH 047/817] png icons from nomadic and my rastered icons in raster folder. --- files/opencs/raster/.directory | 5 + files/opencs/raster/actinator.png | Bin 0 -> 2297 bytes files/opencs/raster/apparatus.png | Bin 0 -> 1864 bytes files/opencs/raster/armor.png | Bin 0 -> 1908 bytes files/opencs/raster/book.png | Bin 0 -> 1442 bytes files/opencs/raster/container.png | Bin 0 -> 1570 bytes files/opencs/raster/door.png | Bin 0 -> 1715 bytes files/opencs/raster/ingredient.png | Bin 0 -> 1624 bytes files/opencs/raster/light.png | Bin 0 -> 1069 bytes files/opencs/raster/miscellaneous.png | Bin 0 -> 1518 bytes files/opencs/raster/potion.png | Bin 0 -> 1876 bytes files/opencs/raster/random-item.png | Bin 0 -> 1612 bytes files/opencs/raster/repair.png | Bin 0 -> 1474 bytes files/opencs/raster/static.png | Bin 0 -> 1518 bytes files/opencs/raster/weapon.png | Bin 0 -> 1064 bytes files/opencs/scalable/Palette.svg | 569 +++++ .../scalable/referenceable-record/.directory | 5 + .../referenceable-record/activator.svg | 1088 ++++++++++ .../referenceable-record/apparatus.svg | 1058 +++++++++ .../scalable/referenceable-record/book.svg | 692 ++++++ .../referenceable-record/container.svg | 1899 +++++++++++++++++ .../referenceable-record/ingredient.svg | 1112 ++++++++++ .../scalable/referenceable-record/light.svg | 1513 +++++++++++++ .../referenceable-record/miscellaneous.svg | 965 +++++++++ .../scalable/referenceable-record/potion.svg | 1161 ++++++++++ .../referenceable-record/random-item.svg | 156 ++ .../scalable/referenceable-record/repair.svg | 1280 +++++++++++ .../scalable/referenceable-record/static.svg | 1141 ++++++++++ .../scalable/referenceable-record/weapon.svg | 1206 +++++++++++ files/opencs/scalable/status/.directory | 5 + files/opencs/scalable/status/added.svg | 969 +++++++++ files/opencs/scalable/status/modified.svg | 1192 +++++++++++ files/opencs/scalable/status/removed.svg | 969 +++++++++ 33 files changed, 16985 insertions(+) create mode 100644 files/opencs/raster/.directory create mode 100644 files/opencs/raster/actinator.png create mode 100644 files/opencs/raster/apparatus.png create mode 100644 files/opencs/raster/armor.png create mode 100644 files/opencs/raster/book.png create mode 100644 files/opencs/raster/container.png create mode 100644 files/opencs/raster/door.png create mode 100644 files/opencs/raster/ingredient.png create mode 100644 files/opencs/raster/light.png create mode 100644 files/opencs/raster/miscellaneous.png create mode 100644 files/opencs/raster/potion.png create mode 100644 files/opencs/raster/random-item.png create mode 100644 files/opencs/raster/repair.png create mode 100644 files/opencs/raster/static.png create mode 100644 files/opencs/raster/weapon.png create mode 100644 files/opencs/scalable/Palette.svg create mode 100644 files/opencs/scalable/referenceable-record/.directory create mode 100644 files/opencs/scalable/referenceable-record/activator.svg create mode 100644 files/opencs/scalable/referenceable-record/apparatus.svg create mode 100644 files/opencs/scalable/referenceable-record/book.svg create mode 100644 files/opencs/scalable/referenceable-record/container.svg create mode 100644 files/opencs/scalable/referenceable-record/ingredient.svg create mode 100644 files/opencs/scalable/referenceable-record/light.svg create mode 100644 files/opencs/scalable/referenceable-record/miscellaneous.svg create mode 100644 files/opencs/scalable/referenceable-record/potion.svg create mode 100644 files/opencs/scalable/referenceable-record/random-item.svg create mode 100644 files/opencs/scalable/referenceable-record/repair.svg create mode 100644 files/opencs/scalable/referenceable-record/static.svg create mode 100644 files/opencs/scalable/referenceable-record/weapon.svg create mode 100644 files/opencs/scalable/status/.directory create mode 100644 files/opencs/scalable/status/added.svg create mode 100644 files/opencs/scalable/status/modified.svg create mode 100644 files/opencs/scalable/status/removed.svg diff --git a/files/opencs/raster/.directory b/files/opencs/raster/.directory new file mode 100644 index 000000000..7a78deef5 --- /dev/null +++ b/files/opencs/raster/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,31,10,12,5 +Version=3 +ViewMode=1 diff --git a/files/opencs/raster/actinator.png b/files/opencs/raster/actinator.png new file mode 100644 index 0000000000000000000000000000000000000000..0446af22cf7d4238e06d7682ab5ec86127b103c8 GIT binary patch literal 2297 zcmZ{lX*ARi7sr2+b!?S2`22n@r05bxw9> z^a&3Bmx+@u2Id9;@G%8)gk@vqEIv0)41tP1iIu;TIOI)p00=$@0Fguh_{}UuE(3rc z2mq^20HB=-03u$wjn;5xgZ;jl34%$c9T+u5Fu~=8wDV!EKK$z}kN}Mw0O06FAq;FW zly$VLSNgD6cnjljqh$tyiWEP+dLoMS><*1|p{VYgzjG-~6k=+-Tw27pJha7ule}iJ zCjHo-@1Xm~92G#P9X3(>6-s7(vyD7E^(R zY|+H&S)R1roK?+@EQ}5zxj=k?*TJtLS8B4(0LhYFtdwhEGFBDkQ_??mI8^AuH!gID4Sc&3jLI6eP)tANo{PpG~ zaSm&o4Q=0&PfBZ$R67^YrGvI?xmQh7k17<5#{Iyk(x-J43&iRoQPZs6|=c~?~hpWO<)=%C!K4rHq0*w?(Z zOC7`(HWg9=q|J4gPT|rJLH50I$Zb{m>(J6qH** z;dZl6nk-)HhLtzN`6@^G<#C2L5n2$7PHJ~2W*Llvw0!=N3Xu)rCJ08YJdw$~&q&n8!U7?6S7tH0Um~iLog$FC%$~rzyzd zvfo@`qXO`LBSGVy1fHixQF0gKQWA`A32wqu($dlna2G#U{+w+3Gq%HBBl(zo13KOf z-l!a1;>{F0!(a^q%~^@37a&2P)2x5U9HHq{5;3eeD+()`F}UbtW=56ai4&d2AiepB z0wfp*>a=P(j4yAAP{>$tIkrk|l;De4)8qFz(Q@?cc)uh-_?hU{LPXkv(j{s%c6C{L zIR?AjlX|22uF3}(;Pc|wj0|D=?=wHA#-~&t4V8|3CJ3dl%myEZyjlBQ+g`Xb z;3p||IVMz>-}HQ`Lu6ZGDuU~^h_-l8o=9|iTO2|z%dF(v;cE+%hIucUFb$8ron7f$ z5~lHmP`>0ve|NWu@53V#4+Jkpka>lkP8py7A|4y%eg!h9Ua-cl?9l9-do5%mzS^bF z1C8d5eJqpnMK((!5^oJkOpf|*ZhD4Pgktlw2;QqSh?}%JPxWwN-IuMS|CB^n2h7Cp z_RnlIe0#S(-Smh4XGdaiY{)ABwbH{Mde5LDG*b*3jK=LyH9C*t;xzfVQ@FPv-tI1rlDjxq?EYBlwLw^!DnfrR@Cm1rW$W&R2uH zttxR3)!8%fUyoNlrYE|+g0B*SHCvnK(~IZ0>vcJ99R)9Pbk!=LWFw=BT^W2`26E3u z4GTb+=~JG;p}>3kGNR=`U*p);x$u7SzN{B|&UTv!R-76axHpn}NnkM0Q?fX+!N&7}ZvfUC4+I1RD7!v(^TA=g@XDUvE;$?Uv& literal 0 HcmV?d00001 diff --git a/files/opencs/raster/apparatus.png b/files/opencs/raster/apparatus.png new file mode 100644 index 0000000000000000000000000000000000000000..613030267620c5a7680dec1cacb012a6cdc7e5d7 GIT binary patch literal 1864 zcmZ{lc{CgN7RP^)Al9ZELQ85Wu{C7I2nLBvZ7mu~rJV|~Or=I-jCB(E+H08nyr zB$6aV9VA>vQX}Hx)+B%hMd#GM8pDFuLS z$tY2sr%KNj2-yEq^C+a`W zlh;kxakouF;g{19A!aZmruY=!-+ffy&ye{6)u7HoG9AFdRm%j2aDAN<{fYc z9j2o`dSul)mp};%bH7pTc~i?aJm9x0M%;`10Pbe0>Q(V17jm^?Aew{2Z9U>~R{N+t zb*;B?WP3wtW8KH3Y=Yebaj;?%bF$#`vwOOC>s3Y>jOE=5kA(`Mus^@EBjL4XlBjri zbMjvGpo#BZkFTCy{XemMv5i>?-CJBD>qZkh<7wl`9wdU)&kf|5h3zO_Q|#&^foti_ z-SFGHXK0YQPia3`MW0ae^8QRyvOVr0&mDY6ws(@#g`r>t$V_-1yhBY5O?5fSP$@j` z*S2&E*e+@`H;^N2E#e!(w?r44;#W^wv$B`Js_CN{xkm`h;RJ2sAVD7Dr&xg8x}xk> zVv#(ZWqmhQDAbsLGMNZwH8L8_-Emv(N5eX^sAVJVy%p#>Z!Z)JW~I6buxd%!M>3Jl zXwQZlZJ&N(hyA>tkOaq9N^2K#&LmmA$U_=Eu_LM(DP=a~E>&|O%33!69_{#|0i(Q-KHBm&D5q=2{bQZn z$oZn|F2Uzuvs<%++KN&s-QDn9iU8px2jJdb52F_|xR8d~)whD$5qx+RwGtsk_|uhN zKAlPe*npuz$3hPsU2U3x7yG%jmMl1*s`AJuoU?0c|%FcRQ`RyLWctGI_r&Gzs-US)rNUmpr{a`jGT` z+Rh-?;#9p%`InwD1^?Jv{bZ^MFJ`Z4o(;oI>>CwG<78>Zv-9gTm-W}eugQ+D9t$gm zu+QoXcu}-B$kq2}r|1wk+BT=;I$muhJ|aR@^hfA^1*fi^k{Rl(taX|o^8BZuxbOjU zuHrA%GctFeo|OX+Rs0zd$`_86jfC`aY)o%uyx_bG`PK-*+foDAdj)toJ9Wp_?x5pI zISK7n;G3BhESH3H*5siS_jhZbmu{>UeLvK&FeZ$GF`J1ff!*L;CeSWdHceXLGvAYk zLVo>~y(1<5I~h7K)!e*^j(yI!0P`<_|2b15D*541`BRTV++jZ1g4WU(HEWd(evjW& zhO-j(SDs?y?7^uSo31O7eJyHGnz6x~sdW3cHs8mjXfwB3x07LAJ}u+4YslMLmkple z@EdD2q#P-#Si@*#lab-S;!xiD{6+QWKBPF`BOj&-AN98U`@4^)3qpeX6ssqoJ^PWw zfZ}^KDmkX&wK9A4uCrs0VxPl0BDu8@blhW`lhCaumFC)c$Xr@i*HD(t?ozex5)Ph> zdQcU{=G1cP)(ST6ycw@|Tc9fwn660X98Vboy^u0ar8a%MexE&&z}_}mYAbh2EQ0I} zE4{e?f`K326IRZJ!-h^GEHGOMIUa8;9^%SMlHW;Mxx1rF# z1I-NNr80lv2j=I?x}>MSaEekB_DK4$=SH`He*W0wa-O-u)3BkK8 zJ6Wk!AsG$CGi}#vm~{N^Z!WvtS_di?+@f)CI}uom>U7H2D7liyp&R+*rN{uk$UsYK zc%THp3}cEl#$b)HrkndGfNCc+$wJWAH$8%fNMdq|KE^SY8N9hAP+8h rga$>@{lWtQolZBoc9RxC^$QC$2@MY}TC`S|h=9|NuEZ(=Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000K#NklE*K}A7_D%3jer7Qv#!7?%mg3)T9 zzUR&m!LTI#gPD*w$?rMOIrp4%*8x~3vA3^Eh>u5nTpZ$JV-Xt@gXrjJL`6j*GBOeo z5fKOv4@X#77(zos5fT!D;NV~=l}ZE!1wj!Qh`@jV_;`E6*kTX(;&|{xu`srYhLJE5 zhQe?dSchV>RWLSL24SN`AT}9V4ibCaf`H4HFQdD=8`rK~!_})-(b?IFOP4O8qoV^C zE?huMOAF4OJBQ}xW}G>52B%M-MtyxfYHMpzQ&WS=%1T(<%HbT;4JTy}928xU1YCxl ze>+6JEfC6^V70daf?cOz=w6OZTNVkhx3jCdc<~}0K75ELPoA*9(a}+ijErD-co+i% z1L*JX$D>D&@ZiA%+`D%VckbN5?c29;>((vw_Vz;R9*U?VF7!`EyK7O+g;GAH`?i;JZ%XMB6_oYE~n+ZVov=y~J1F zPGeu$6cP$2pv)S8RMCu0PPy1eVYed-e?X@84e%WnW((Zrr$m zo}M0DzkZ#i>&lfY*t*>po-w@$I5Y{r^e0@T!|+P$$DWk?*q!)0cE;a?N6d9>i{d^T z-od4$0S4wCFy;x`G&NvnYg={x{CQ?6ML97sp%XkbIvYD8ujveT32A|;V+xd^F)%YV ztIJvnRSHFLG)hWJkd~IFEugWnk>!{Qi%!5w@bZf9A>DIA zZ@BArA5>ISps1(_si~D*F?e}- zIaDeYl9Q8R!smZT0STz9t7FwoCtzr3NUPc#8qYDfU;4OC)lLOx=UW4zRIY)Sm6ahs zKOc#SiAx2DI04kr=x9w&PO`?c_^43_l(@(02lx9K#sY^W@Y2#!}d z5#Z|Ll9-*H4eEx2gM%0w8)IS!?z$reUa5cT1vj?di+okF7QC>q5LsDSkjv$;FgH)s z^np*;uU}77jRwr!yLVY3(m-}BD{jvZr1(9yv`O-zjd zdg1KkG*(?*&8(+1_y?uHBcfX`IA5B$Dm*VQkJ)c75R4IXi2ye@w;HNY>WG;+1xQj2 z=?9m@A~Z5-#mEVsk&yv^e}7n7Sk!036Mx68vByf?UH{+-m5}crMqd3KRE_g1PBjhOvjCo65o^M! z$Q23&4WSzg(Q64X7jBjDY$Dhu6PPiC!X`Chavy7rR1JLRafl`EYr+p7K8!eS-Ltp1 zR|^CJ;}r$a14C1nS&N;gu$`On$;E#m`^OiYfL}H9d;u=@{sAJ#y*k0u)6)^a?TjBs zujK%}A+U0h8JK(hYay$LEa^9VSuus=l5w_7EQa$fU3G%zs~vP6bD{6Fey?37(#w z)cI-`Td#ErK7P2tQ2c(2YY``+0p9!j5R*U7Inu+e+TJ?DY4Py$^CS4ga_|)$pa*<& zsq71$E4RUxaC=-G_NMm2(kU9Mf?}N_r@Yg>for+5T<*23U(*3rkS2CbpYuJi!6^@X zNhFS+_=astZEbCAu&iWzW@aY4#BdGg4Yzu+p0Bq93t!l5WYziEW-G}3!x)ejmzy_l zvWpAV!N)nL$O-Q3>^#piHa@f(eAN^z{vx-%s2m*~)wD`cyQY~zH>j?zE}T4hQd4jX zwo~M~z;zZtAGEfzO61z;4BZ#0rxz3yXs&5g?I|fKtl)&!)-!9_zG@>{%`)zX#hj2y z8Yr|@QG2C)lPH-?2JW0s8W|ah*RuV83!pD@L+cYWGqWzKRH~+2(@mMXS*f`+bLX`Bp?o`MC0000N4M86b>u62;YJ)%L!B43 z$qR^=l~sJ*BJDR>qkY&z`x(M{d3jr^kA6JuRN|Uo!nZ6xhxW*TYs4Y16CV@$o?~R? zBJ$%OWCB@{eDMr}gb>CqLjxm`bMLiVE6>6L17lf>hR(UHYoKS8@ERb$1r3tg z<6UGCO1xVW)HnB*>yC|RlMnmWouPDq`G50ip#OsU+G>(1g8IKNPQW{8=`pC7C z<^4In6h7f^ z^x}B(RGg-6=Cq#FCfvN-%FeP1b@cUI^>BFHDZGLH_qdaI9L~FTmHHpUrBF(6VC4TBPR!YNK?bFR r1eegjaE2c}05BK~-Qde1VPrpQfNm%~D0kUJ84>|IYm!xkg)j48+bVhF literal 0 HcmV?d00001 diff --git a/files/opencs/raster/container.png b/files/opencs/raster/container.png new file mode 100644 index 0000000000000000000000000000000000000000..7874606ab9b905dd3afc5e58b929e586241f3fd5 GIT binary patch literal 1570 zcmV+-2Hp9IP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000G%Nklonjx#Q!6{gxwt>Qc} zb!j`T9sLEhJ-wG1I*QqVAHJX7yZ4;$eBV9ay<-53@fL+fHa*KA>T^Uh{2UTxQ4Bvj zQplH*C@~57Vxy2RiV*UJBnrZXd>)CJ1|gpm!uF+wGU>kd_XtG!kF5C78H*pPW6)h?!S!WkTwNNCON*m$aX}=`&o|-Bya?>imm^WbUKuq3nN*ss zm2*#9vN+scnSj6AO7X|85iz=Ll({v0=1JxPzP~O>Do~f z7~G&Bf^pHzA2#RW?z(i3nV)ooBR!OH`2rsN?z03Wi?JDDqTQ?Q(ic?rN38|;sV>>A z>=gW1nE{Jq#V-=n>~6Z&7ZHyH=;BnJ_(E}%`1#S)>r!Dr~XKD1mOj3FMKErwvCl zzg24+75J`cN^H+iz^W9wJsEBlpbke(hBn-AYCbgcLGTtkF(qXH@3#V_CgEf1aMWbJ zueQG7a6`M@lkBg9H%|#hykZyxY*F05H})ps_Z|nj52WGZ&IFumjmPQcI2_v;i>?L> z4y}*I!B3;mQ5T8!8Y8}RMqpQ!0oy9|*s@56rum_0bcCROwi;`TRR~iA{^Pd-`T818H;j_DlMeSrR) zq+uMj@eB?YhvC%1NPI!0r&Em%7GE`|vQzL63<1av8V8*uz%gtB^cqzh&h&phLxW=# z#Org^!v=p}CqSHZV*iM)WR!7&is{{vA;*z&J=$k#hLt%5UlcMC+CX8iw~MLQTd`Te zUimyJ5c`X?=qL>FdemN*oq{jbPQontSg0lJh0zeG|IjQ%+jJG_1&zmZ?hbsBW+J9? zW1$LU+};KKdKXah$kzp6Yg#b&7pkx+MfR4-cmiLbngFwSf=2`Livay8MlN)1n9PwL zP++TF`i8@K19!;BK`jpO`9kvfGBO6US87QahT5w)@CwCv%#^$Xg_s%rPx#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000IeNkl|Rc-r7L=Ih;te9|F4 zjY{HX#4bDt*#ueb-{YTC1+LR---$@#qt<}w<;f-q>)jrF)aS>QULP*^c(I=I;@lwz zrc)L)xWt!!tNs!Hjv6BS5~y(*M#GZ$e7V(uTf-sTn@-@XsW`rzjNyxkC_W#H;?8IU zpN@p_$$KGuko90ZVS?A9e_kyMx&27&Nr1trUU8QUS^&Q~6vAA_jlmij11TBPX&2T> zky}SXxH%NWwE;g)Hrf!j>0gDd`q8~e>`H+Bu67z;Z1nkXeHe67JPmJm z&fxb*iGu&HgWntu;>J)w>AuNt#!82a2GoP)Rv8Tr9sFi(x)_O~1VVQ4;R+31!E=^< zug-UZUmfsajcjNQS!g>vxRj+?2@7xXKew@o~eeWgvPH^sgwo$@#gM^EnPR!Mq z5j1P_sukdbyFM6D_WVqjUm;NnILpr9)Ae?o?{H!!Wg-Gq>IrbX^6qoUEO+^cgztaT z{<`M{*$bYt>{A3jS!c&;J0)bb5dl*P1nP(Y$15k?=}s?BcX_v0O%3=3l6|7ihKX7m z&K{C6nKZ&*3V~XeA%BVTp7(pH!=n`Mxms}Udc4MpkwzK4H4?H(N=3W=57jeJ>lE{A zU2Y}Y7u!8(4qDKgw4*0sLoRMZHf}|C%!;n46`c`_QXOG4+Cyfv1x+{Xf@Q;FA|p7W{|{63>}ZO2lx4U1_jy#=f|95tacOv6aT>Ro!cMUDC`NJv6{ zIU_3rcdXfgqg17UFVtHw5H%7BBaYXb(eKy7DQMIuVM5a9ms%uc+K;AX%r(i%RpW%) zuX6^UuOrZ~fk+rIUu#0Ij|k{1)Dwu?_4&oLU0F2-=fhG8_))rkeIb!Zh~V!YZxtM+ z5Qq_hQ%yES_QF+D+c^WyrHtqy0!)Ixvz|)Gx)KzK*>rh+&lRp3AC|oat{{5>e5Trf zTtHAr@OQUM14&!1-hwC*SZJ^+vhzvh!@}uSY}$)~PbEZj`}N2L1xzPJbUI5U5V7j= z^E6BxuY6MZu#^Hm5f{+q(;-VFCgUPH92Kx@%hW3nwrcaoXp%YG`J|4ftZ(f3Zk;pu zSX7S=k4{lxA|{|sE{CnE6ap4)o}W?d`|&0_S}EbSQ_f2%=Mm9F)#&CD=-)8`^-ewN zsA}m2Tq9FSIt&K&3Yk`^4A#mL2!x0LKcm?9Lbji7vEzMCx~8q9JJDcKLWcKz=kT%T zEIW73;G+>8GPV*4@B?xzCSrj=cox`>IRcucmEz~sRMLP68nkf&8I1}UiRf`8tiw=< zx(;YD;IBfTuM)l9O61%c)EnQ0MN@(THc|U5Y_39xDrl-i&{&B8mEWL&Pt?Fm8DyqtZuu)kx2O(Bzo)vo${RhGC1icE4k}LoK002ov JPDHLkV1nG+EI$AM literal 0 HcmV?d00001 diff --git a/files/opencs/raster/ingredient.png b/files/opencs/raster/ingredient.png new file mode 100644 index 0000000000000000000000000000000000000000..6f9a09d2e93d64c118e7d375868068f77a2b0d02 GIT binary patch literal 1624 zcmZ`&2~bmK5PpP2EJtOSS}CGKZAHsv$N@<}5J(`91VR$7@t7c@bqW$lLI|lEA_#>0 z%1Iz7cpyg;4oO5gRJ1xe9)+TCq7m zwl2011UW>Ki45S~mYS0r2nq;V!>KpM20{?5mQH1n008;`iNz3CiRLNLISn|G z7B6Z7hrp@x<*BfO2He5sK*_1#vTkyDZxlz4-m63lwK!>4gmQ=hV0e2^hfV}%<3lCFsSGa;a*><0hx-bm%}aynOuDeNRx_EA6;&;y7Rb&|MB z6zH?8J5qEEFVx~elUWK3M}|7u7J8^TP%PdisP`-BBG;UY7HIr)8gZ3psRx?_07J!D zic}Y#DMw}3V*y6o>Ip310koMi6kqKJ$Pc#!a#ffQA9XZAP^QdRd}6Cei{mPmgCGJ3 zbDNg&K^5?dZv3Y)F)q-xky+VCRSh$%4K&3NLo*UzcY$8p zA5+>z)?7)bABit$3p?5orW|H~Im!lNmBY-^?nuQDQ>rJ+2V=q1r1}W($#v)H@_|^O zcC|6O_B_4jTucoh>0TDUSQlPxq*WPcg`K1-BMtOpZsPmYYmwBD{Xltk|%3{zjF_{C>0bnla1I&cm3=@jk8Cs>|yB{3i@piO&Dm=YBwc<2o)jLk-_CN4mpVneqbiS8q<8pS(r>ABnr_}@O$qk3B((Xt?hc}eSy>=RT_p)NW?(Cj&@{~!2 zuC1<4eB9EU>UM{c&@QVBlh-BCcUaf$GG^(jQO160s|z)E_CB97ioNw1+wAb4zoe~oOoJa8{VgxwfROgLjP8by z>o~9H(#QO+F7##x2!@8P(LBY26IMxi$M1&X#?L!Z@yEv>>62Hv&Le6%4qRP$zJ9G6 z`{9LyOKd@oAVc+5v>V>->Ce__c0Sm8o=#a}FPPmX@{4QSk8gVPoulbA`)2nn+8H@Wt$gpbB9Q&2 zg~D}yAu+sk!$7dN!NDZat36-^Hu6Y`ygkXhR65KM8qP@|+EMFu6=|{j~ zJdr2@5~+5&Vfj}=dd8mpdxig>Fc-rQ1qoj*S72uBnf7!9< zX67ZO3laK!FGA{SgzOknTM#NI5L(Jbh}Dcxu%fk3!p3>0#c5JLCV*$G&A`J>Sk(ip z0a(FifR&qYzZU-d3G6dqv$|OhBdlv+=Cn)yDg0g!Py4`z`Kw@CfM*l1(gixTYx+1m zYKM(6fCaEGf^8BWUvipME?qe+o`;Q50E@en%?PX4T&4=wOc^Y7fn5*li*Eesgv(In z(jSAhL9j2uXpCi;GdGa6G?;B2=Q*aiaFg@oF55a52P3hL-#CtGKHTGw`ZV}QtqsdT z2wSY&@tnn>XFd;l_HJCuCG{dOBzridPDC1I&bcp~mL})?m!zr4sZH@5!5=x~Y^lrA z=$u!B;jjmEnu?vX%D-mM-e?QIawfj-T=>FJ;@!)vJ6*Bk-Avup1X7nm8s8^p%N^z# z(tM13P(bR1H9R&`j&@@Au`*qhfzYNM3A=n~(eF)`vx6vvtd|@p zX3=PT^}=$4c$?3`uO2zhNVa=LeQ35HkN4dYKW0eXMr~a-_ry_#N$dmCvs6EnDt$AhnzVzpGT5#AN?`HAdx14FXFXe+&0T0zucP8QB zB}Gzp8UBm-rRWZdk1DzagO8JWTq*NTUas2f;EUJQb>G)C(ND4Cyx$Ct^$QnOBvewk zyJZ2Ah$FPY&^J0t+vWN5ihT`PV(FOVkR(&n!O1z0v0rdlkmYyr^>w;$*|*;a6^>g| zY+rOW%^Y&#lECoqP6C5 z`h$ACdSCHZ47c@bG@7lQ{XQeBLl^powOYT4@1T~T6AXoawUItR*!+*w`__z{ z9C$YCPYq~P6beqv{TM(A*!pVl`G)4|m){;`F!qgbo6dfBuCXrgvuwS82!fbO%gMG( zE7l#Vozo?+% z{}a-fl^Zx=ySqb1Nr6%&E0rUaN)=Z0NpV@8Od$^|DJ^VSW`|%BO6H4r-HEwXe*-X~ B{}liL literal 0 HcmV?d00001 diff --git a/files/opencs/raster/miscellaneous.png b/files/opencs/raster/miscellaneous.png new file mode 100644 index 0000000000000000000000000000000000000000..b6cb250400cb65c921d4ecbeb3ed0ec5cd0ec014 GIT binary patch literal 1518 zcmZ{kdpHw%7{`C3&1Jddek~#CqUJIQhh%Px+(taeT*hW&%Wdl67?o1F9nNGVj!QZ@ zN_E1BNlF}>xrIeTb2}14TIqD=&-2H5pXYr)&wKek-~Zlhud^<4vRbkL068~Tl#iHt zJ1Gql*Mv)#HpJK!?cm`6Kw}G=Tk!%Ge#QkQrZ_~7t?6ROP+S8O#Ma+-5(1|pOT~8WZYT## zK-Y762ua0H<#qZNdztM{ZTk56GF=Vd`O*m8=;T@lOH+Jr;jJIDx+jNmeT=% z!;SfH>?Y*=#+xyG1tdZx(?MiBY3u+!B*fX%vtnCu)a0lJ1>UQq@n@}qS;NA~@dS?O z2fJnKuiT1Le^2pwCN%*cYnS~vE4a3SFQg&az&4_8Qsb2=B)vL$qt-%UdqtNS0s?!& zIaR&+0k!fkyy4_?ZCKig_L&rJzVbt1a8^eW^V2TcdHks*X0fo|X8%vuZnzgs0(_fhCM^Kk=0S6 zz{boE0?5rGY>@B4@Ar6w{X|Si@m@Wvl#Gy@S|@KWuG@ayH`O`PZfVK62rt4m3KyjC zD<1-$rIQT~(TMXWdGFqEN$F&pTAyt#Ld|rg?zX8m>xX<;s5bn{Oj*&pyJTonqSv&# zSM{!LQ9Y+T6BZ0p8T+n#HP4u)I1Hye_0~VgTNB6)@X)R@>?7I73d^o{;~C0eSH|t2 zTcN%ffm{Xr=(Oqn159Zpb&2%KnS$iK?l~89GVl}ZW<|`L93LISNJiA#Za6DTIi-`2 z)IiNJe=NLMQ<>?=`T(KC889eA>p86B)~v$n>fRqZD9frtc@R)J*nvzM)Fwm=>cOm? zzoAa9q&xQnRmmyBtsV4MotB0{Fj0aVF-XTUc|>Z)H~q<@i&tFo61k66A91PO}5~Ma%)#AX^iyCg>7p-L`F}33|5ZJ zyQ6)4$j)zY%GtSBUD0l&>x}Ly^pwA&@ZfJRth{4?MRhUGD@ov58XmZ5dItDgsL9@G@sDZS;@VeDo@~M{^|do61}hu~ zG&JfcbAB(gs_h;n*|r$rZ;_7+$Ni*Lg+((XW_2MT#J+0;R7Cnn@7Y%(ohr=L+`{ zrlF;f_H#0RSrzImYuCfR&!<6L;z}}u)mCkexQ9%8u=9Nu9XB_V9vSh`dlt-0mWNo! zD|_ba8M0DS?1E9FP}&p6&O54|!&yG-bCN%+lT0Qvnlqc>-OkRNTKR*%50uNSVST#B zrL~irmPa|wd2C@_eL+8RZObuhy-nb0BL6kEuXMRak$?D2z@WWV*f;r4%rcF@rJB)b zQY@ZPT~&D38&VpT=I>cT7(I86@rGW(k%4!X%sbTRrK&4WT5#opm5n&YEF>-u#>58qE P_z1W;okcaA#%BHtUqPk< literal 0 HcmV?d00001 diff --git a/files/opencs/raster/potion.png b/files/opencs/raster/potion.png new file mode 100644 index 0000000000000000000000000000000000000000..e644017641207da2d8858c2c8b00d0233239f55e GIT binary patch literal 1876 zcmV-a2dnsrP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000KVNklauk_J%ZmSs5?*aciz(B+6AA}W`lBF4(02~iHADi99QfI;Mnpj3(|5d;OKfCezA zfGC0k!s1b@rqy&leU}an1d+o@|9EEinR(ym`+2^<<9XhBz`VH(x#9d2N2B>Y);jO> zS!ur$KbJMs@61VD{i2V>n`F4pW4~e^j=FF4{$Bu0C3a?dhN6d7cFrn0kuG5?%n4DL zAlB8yOsY`n7>FJkTgc3212ZcJ9F*SqKAS%0>#CbXt#YI#Bb@5}p?FG-Nhze zhrtIh{150KfsQ-SDzqT=XcB;`1vk_n84W+Nv*Z@O@h8wWGQX={YbuZ_0W4&St7`G$ z`XSo7K_!Sjd;;Br!tRCn>2@el z+7UaifAq3YOac%}tu!{Tj;0@;(%;n2z2P6JTAo0;JdWz4SEdB`CbNYk@kaK1?<7_1=v~f2=~}>bS<4qf9}F004L8tRqoNtG;Ycpjk&6zm48K4(zQC9GPCWJ zZpx*iy#GZG6j!P^9Q;=&V{Yqp|CInD zOFOf#yc1}U#c?;c8I|fe&yQc@r;1JHa&Yll(zSdzsI#6El1MJP zrqUjoLuX7r?Gf2r5F9AA*(HDk6aUF7Lf@65G+o1@rPdQp%Lxuh4f6)}9bGL{Or zX!bAm$5Z=L7MaKj$A@78fUS#n%_(s>gF!{~x7?$@xN}r|Af$x8z#@A5^6BzBO6SIW zIyU6e>YvS}wTGxvrcmXy?}d1&&2ElaenElR4vvVz$u`Ov;;q?jPW45boOel{Ryxw5W3MS}nDc1V#Xc$VSt^##zK2`WXI40Uc@8;uF2`#rVvu!ln=VH5h=W6l4 zd=kKl-{@jsq7;s@iD$y3MkJQHlpZh*rNtv{RJ^SI-!umn&N}Af#karbhU_gPw8Zl1 zJE7387p$@Odz!5mK)YWaC(G_p8CO56gc~m&_tAP3zt+Y`*YW9$&H}YXhL#S6U)qFG zAP%Epeco${d;i`Ht3TSIu~a&t{>MTw<$b_dB)t{A)L*FK;2D?N&v&jCw|-lUrjCVh zZ<@t@K>e`VE(1f$p$L6nl7)k&Toyap;a=8c)O9{yeD}gNc>Yc_Dz2ezGBl?f(F+KP zbK_dEFX8XY1(0>*inmYbaO1^eK3pS|n+*A{gip0U*`q0TYM+*bqbyCLONrBv4s{J z+xRUpTUIMJb{erU^?YKdvmEIXXUs+JPxK8OMl?nCwHk)jelrmsd*;6>wBw{6A3SOR O0000WhV^AGn&==Nvijd%jsxGa8f0J_;jomDf%A^dQJ z&d?E(7b3I_rt(nI`NGmZaOvnWSh_0@#m6er7H!v{p_4Tc< zukY*Y16|_;g1xGS8$sZ^>=CW8jNyu7$vZbwH4g+jsO@!sCvDwWE_#Dv4)@cI1J)z$g=c{ew= z#>U2`rl#fPgty-U-tC$6c!fJ>2w~C zx45|Y`0-=tUrS5t;lqbSB5`0~prxf{aBvXXtE#GkibX|5wY9ZNOH1wT?Ik58t*xz= zmX>X8Z9r~rZtm~zhrQ(GB~jmmmw{n11YO6&`4}dn;<-{8h9%Qtz_3XH^{7r9 zCX0i@YDtaT1{p-*o9gRXxuDF3uE02ne z>wgWq!X+FC4n)NS>ku&XGD2dq;FQ%Ty^bU2u&x4OBs9=p=>5A`utv@-II9 zs^HRv9Ytgjm6esH%tI0rp2tZ&f8)}!R(l4cZMW+#B4M#k^#`fsgDwTJQhDS2 zb-$z9bi&trs{71RBn9o+(&Z%sKmGjh6N$qy@K?r;`~LicF+sNJMAFh?DN6J0RK`@r4ck3# zL}zNNgZ(#39%Znr{a$rJLc;XaJG~Ug;r-Q@F0zzM-Q9vHO4aanLa3tZkr&)c&+hI! z4Lr)s%&;S_Aj)$$&53qUbRxF+*?HyE#ZUMn4Nk;Ao$8AN1os3nJjyldIsGUKQ~2at z{F5m`RCIko98SF7p+Z4F|IFMt<=l;w)Oo){rM*M#z4;{knM%^B+*CPfZEcsMd}dcf z1t+OXcuOG>To1cqC}fJ0#c9HprZ;s%JYLqbo~w67ldW74p~l?(NDID9^`(35QNu99 z1)l4nn_8AlYi86s+{o>L@6F4n26om@+%id+rI&9c6DN)zNK*}@jpW!~9F8d7aDNwD zoqIob^{?QSbzJF&zxQhIq(e&Rl}Xiig5OG8UwCWlc%L*4&_*pjEorRR7vOh_c1pP) zN)zLyNj~DtBmm^e^zdRZy%=5|LJy`7lkLOuc4d0{FquahYD)eSkd~e(Nk0Am0gQPX w8v-oV6$I(Y(wz9rB$Shr<1RUonkA0UNODilJa+XJ#|lU&lp7IvGeD&H8)U$05dZ)H literal 0 HcmV?d00001 diff --git a/files/opencs/raster/repair.png b/files/opencs/raster/repair.png new file mode 100644 index 0000000000000000000000000000000000000000..a8165827790baac034005d1b4729b02ad45e5f70 GIT binary patch literal 1474 zcmZ`%cTm$;9RFbrib}OARwz`joJC8~jDj>q4Iv98h+!{f2W13e0umr3fsh19f+T22 z$bk?MWQ9l)2pE>2oGb^`sy%Df7VF8<_D*s1(cbm!AN}6veb@Vb?|sJ;2l$h0*Ep>U7^#B(;v@M+%+D*-d9-X=0IC#}EJUWoYJ_*W*JQ`Zl zpwhO~NaSJ;kDW?S4hZxQ2tJ(4J=JDxl2=LT%v4`r($1Ybsln8$8il^QwawU=LQlqc zWAeG|JZ?^XW38d9!!p=ovgngi60lgTgM$N+Ow3@UilxPMO*MEtrqk4+P@ZmV)~aii z3A8w4uTE!bj!ih`;^Gn=6E2kSHT7pzwF+)=UT8#M#L=*@s9;drDGn)IibzK+RO#n^p#wIYUHbY~p z;X==#VPtIJQcr7VZ=0#F!#rr{8!-=$4UFF!othr&9WwO|cTY`^Pu{++Ij^j)KclKs zsO!#Xv}aZ46w*p@NqLc=l*=v7&E;iD6=HLr(K2M#XqB9zoB}~kp_n6*6_!>A#j?Vp zk^*gW?X`)an|CH|-I*L3wHSJJJYgPRln>@vCKpO8OXO7&ae0wY!t3h4q&inAlJX@A zQAJf5=m?N(LD~m|oJsW$ged-$L%u#fBq9Otjq}1DJg{s1UKA3EL?GaBRL$Q@sT@~q+xk?@cR=0paDO$Ip}{90SEA=@RZwb|}!5J2<6dj)x3kB`~P z;GPy&RS7C3nnHQ0T6k7=3>zTw3d0BaMd7Hv5yTLG&f?|`N_5(rGJ6zlLbabZ8wIl_ z>`1f=c4ygA++O6oblHPlgQ=!c^}4o{Ceo$DXkRJ!eQZ+>1VmRobMjk`JwX3g{T{wCRd>&nOF zKiJwtud|MQbXV*ARejx^mS_`aXvFYET-;+OV)GUHz23y<#uxjtX7635%~{^rh-cPR zcsO}>{WkT;nIv;Mn7MfS8EQ0naTjf}`aXjLBM%5lbN57BDoPr*yX|*Ix$bk>yQi;K z*Vv`)Y;i2OIn~5fA^79la54P90IMH;i~s-t literal 0 HcmV?d00001 diff --git a/files/opencs/raster/static.png b/files/opencs/raster/static.png new file mode 100644 index 0000000000000000000000000000000000000000..b53be12d9a8abad9272fdd7c6a75b1d3a6a494ba GIT binary patch literal 1518 zcmZ{kdpHw%7{`CZTxJ-Cxok(sA*?NQX1O$0o0FJZw8|yq&RlA3g(EHywCH#pXa@NpYMM!kLF9!f|WyX>)eRte=7=CC15NLd8sXdC>{K1z&!_ZHNLb7(&-i^$pDsLJnXU9&72fI{f-7|m zF|gqUd$2u!OSOjh@6iC^h~i{P%*wgaiH@`4-IlW$(-}guq2X=ms%UtDxHc6RUGQ5| zQ>zhiyz0XC}*TygO>%+5Vz7uDl-HQ;)|U@va&5yH@D~XW#<`! zxrI|=%kAnb=H?bkj$U-bym(m7kxFM(ZI7d;E13(2NPkEy1{u+86aA1ThWx&ANizhH zKo`He$h7_2yn%^F_TqCh4xh2V#;wptNIlzEeDFgs?Yd>dXkZ&%gzer{=rwAv>;$*b zX`!pT>D12EEyG-OZamvM92e)I$D?Cf4pAUz)yG>Xo9H290UDwJ?;Nw__%n68?LEg@ zn`h@r*cTwtNv2~WmwqAso-c3e;epsl!$MSb#k0ie*=Y;qeHLkDWwf=g&=isQT(DD3 zXqc)RBse4_M#uj_(sLQ%s}YtqGoWw0-r&1F^s4qm=fc>-PZf>?nap1e2M(huDoCgT zf^1c!rk|G75Y>lcFFVbfntq@d<1I|cr~y{Hbbzkiz1{CmTU6j+>k)ole0Tp$#JluH zf73FkZUN5TZrr*up9b5$c?+_6TKc#W$;MF5Q6HwM;BSTt61JW!(KSAd!8>w|2V0@K zwJn{K)@Td$5%Sau(B&GZC&6j3$K(6RlNvohbDihp9JlJs%F?x$?My$bR=-l-Zu@E3 zi)%q0IpNlAj;D$m&l)rd1oy88Ew*`g^gCd?tIl5<9JzX zW%9t+wQudFPx#aV%X9iq>UJbgL>9=hST6jV^nX@aZ$dVFDtqLXL=lRDH)z1T++~Zl zDV7bT7zj=7x;-{lxH7x5SZRK5COy9~0gixo_0I`!c3|5Dg2m(~(OXGfTQ-JSvB=7_ zqT;CT8*!;w`?SB*evbZ$$MDcog-EF7D9>H~r4-RjcK+-wsh!J1&|A}%l3(;IRJ;yR zdq%x-ry!Jn6l1TlN*7eS=tiK9Rp_?T$LX`*h9bGM6BmYiO9!|Y$KDZKH0q`nJ|7Gg z-W9HE!?=@GFujSr@Qei5TceF%CyOylHr1yDWn%qDkJ{HH=+%T^tHFykf&h(*0qOo$oL@Y0gLN=l)Plry|+wLh+UFZ8q_#K$TFFVZf*vCKO!jdRXx>{REYi(=3D{98` z@zcj()PBW#Tc5ctG&4FfGlm$I9-{!*gu^>J;2a$s@j-YT5x1G>>|%%8M8x5iAN=nA zA3<_zbo>F<{|gGsk;fDQ;~x%zsRuHdk?Apj$z)>VQxY?xA{jB*)b!X&iK~g?2zYPv KB{z9S9QzkRt&Y3^ literal 0 HcmV?d00001 diff --git a/files/opencs/raster/weapon.png b/files/opencs/raster/weapon.png new file mode 100644 index 0000000000000000000000000000000000000000..b68878a54abbadce500135ea0dd77e7e53168118 GIT binary patch literal 1064 zcmV+@1lRkCP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000A*NklC~g8kO*MPy}%<;wSyJmZstM`E*dS zB;<&=YZ3vchrGk4fJgJ68{u|#p}o-vm0Vyaa6T{jpGm`m#mI*?I~hDq;%Z9r5miti zn*vPDcMbUY^&#dyHRC~@7P9Qrwfi+E(0MZhHO54wat<$VgtM9exh!8P`%`mKgD)TM zVcOn+h8s#Kb5bKZXFUO#RBG?)>Ow_%`FfREg{il<;doPvTbHHCI>}uNch0H+0>4vV zkJ;H-EG#U*WGY#=l*lnLbQR+-t6{ZdB3s0>M_PFM?tvhDdU_fwD=V0pnZd}&2xyaO zou+bO>#4-6CuOKUCqkBx8=4MQ5;#Lq{lqze`~7~*&COwKYz)K0!|3blLt&wDy+|v; zKu0m2HyZdo3*t*w&1&3 zLRv#?hB4ku>fFzO4YILZONU zS11(z{lKFNAn;O}c5UaJ4R}NW1kSA3-|>KN5kTO~@sfS+cDoU&=BL$aA2St}z1BSH zCJe&KhlF%`Jm8@OE>%?>(`mJyAl&QqZt3=XmC7Z~$O!$*v6cXVlbT0^x3#rFE|dK} z2zVfY0-eq=I5-%HJ=}RqOADAW^BxpDAb_H%ccY`D@OV6%Vvh$rAb^?o?-LUfAcvHJ ztXBeOR;%YAoriwOsKP?$(9jTUHXFLTyV2Ct6sWmIqdCS_qiuIj0#jor(+5t2!SJ0K i#dmqRxsG_jiLn1=-XV(QI6oTz0000D> literal 0 HcmV?d00001 diff --git a/files/opencs/scalable/Palette.svg b/files/opencs/scalable/Palette.svg new file mode 100644 index 000000000..f42475330 --- /dev/null +++ b/files/opencs/scalable/Palette.svg @@ -0,0 +1,569 @@ + + + + + + + image/svg+xml + + + + + + Tango Palette + + + Tuomas Kuosmanen + + + + + Garrett Le Sage +Kenneth Wimer +Jakub Steiner + + +http://www.tango-project.org/files/Tango-Palette.svg + + + unify + global + theme + color + palette + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory new file mode 100644 index 000000000..e2d80ed58 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/referenceable-record/activator.svg b/files/opencs/scalable/referenceable-record/activator.svg new file mode 100644 index 000000000..0c6db59a7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/activator.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/apparatus.svg b/files/opencs/scalable/referenceable-record/apparatus.svg new file mode 100644 index 000000000..37cef0e89 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/apparatus.svg @@ -0,0 +1,1058 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/book.svg b/files/opencs/scalable/referenceable-record/book.svg new file mode 100644 index 000000000..8c041a9e7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/book.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/container.svg b/files/opencs/scalable/referenceable-record/container.svg new file mode 100644 index 000000000..8c9465b66 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/container.svg @@ -0,0 +1,1899 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/ingredient.svg b/files/opencs/scalable/referenceable-record/ingredient.svg new file mode 100644 index 000000000..a77a9c8ee --- /dev/null +++ b/files/opencs/scalable/referenceable-record/ingredient.svg @@ -0,0 +1,1112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/light.svg b/files/opencs/scalable/referenceable-record/light.svg new file mode 100644 index 000000000..f8f506636 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/light.svg @@ -0,0 +1,1513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/miscellaneous.svg b/files/opencs/scalable/referenceable-record/miscellaneous.svg new file mode 100644 index 000000000..96522048c --- /dev/null +++ b/files/opencs/scalable/referenceable-record/miscellaneous.svg @@ -0,0 +1,965 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/potion.svg b/files/opencs/scalable/referenceable-record/potion.svg new file mode 100644 index 000000000..552c14f19 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/potion.svg @@ -0,0 +1,1161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/random-item.svg b/files/opencs/scalable/referenceable-record/random-item.svg new file mode 100644 index 000000000..d051ce049 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/random-item.svg @@ -0,0 +1,156 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/repair.svg b/files/opencs/scalable/referenceable-record/repair.svg new file mode 100644 index 000000000..b1a23956e --- /dev/null +++ b/files/opencs/scalable/referenceable-record/repair.svg @@ -0,0 +1,1280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/static.svg b/files/opencs/scalable/referenceable-record/static.svg new file mode 100644 index 000000000..a6f29370f --- /dev/null +++ b/files/opencs/scalable/referenceable-record/static.svg @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/weapon.svg b/files/opencs/scalable/referenceable-record/weapon.svg new file mode 100644 index 000000000..2e832fff7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/weapon.svg @@ -0,0 +1,1206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/status/.directory b/files/opencs/scalable/status/.directory new file mode 100644 index 000000000..e2d80ed58 --- /dev/null +++ b/files/opencs/scalable/status/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/status/added.svg b/files/opencs/scalable/status/added.svg new file mode 100644 index 000000000..e0af57002 --- /dev/null +++ b/files/opencs/scalable/status/added.svg @@ -0,0 +1,969 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/status/modified.svg b/files/opencs/scalable/status/modified.svg new file mode 100644 index 000000000..e278ce596 --- /dev/null +++ b/files/opencs/scalable/status/modified.svg @@ -0,0 +1,1192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/status/removed.svg b/files/opencs/scalable/status/removed.svg new file mode 100644 index 000000000..17719cfc8 --- /dev/null +++ b/files/opencs/scalable/status/removed.svg @@ -0,0 +1,969 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + From acae815cd23edd087e7e848cb92b7d51e178a571 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sun, 31 Mar 2013 18:00:46 +0200 Subject: [PATCH 048/817] Added workaround for OpenCS compilation problems due to bug in Qt MOC compiler. For details please see: https://forum.openmw.org/viewtopic.php?f=7&t=1451 https://bugreports.qt-project.org/browse/QTBUG-22829 Signed-off-by: Lukasz Gromanowski --- apps/opencs/editor.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index c242a17ea..cbdbad36f 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -2,9 +2,9 @@ #define CS_EDITOR_H #include - +#ifndef Q_MOC_RUN #include - +#endif #include "model/doc/documentmanager.hpp" #include "view/doc/viewmanager.hpp" From 63424ade56fd9c7da96446d666e4c4e774f1c4c0 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 31 Mar 2013 17:30:03 +0000 Subject: [PATCH 049/817] refactoring --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 177 ++------------------- apps/openmw/mwmechanics/aitravel.hpp | 8 +- apps/openmw/mwmechanics/pathfinding.cpp | 201 ++++++++++++++++++++++++ apps/openmw/mwmechanics/pathfinding.hpp | 26 +++ 5 files changed, 245 insertions(+), 169 deletions(-) create mode 100644 apps/openmw/mwmechanics/pathfinding.cpp create mode 100644 apps/openmw/mwmechanics/pathfinding.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 41599b35d..d29e0ff2e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -65,7 +65,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate repair + aiescort aiactivate repair pathfinding ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 2c5260a62..df6a38bb0 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -14,7 +14,7 @@ #include "boost/tuple/tuple.hpp" MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z),isPathConstructed(false) + : mX(x),mY(y),mZ(z),mPathFinder() { } @@ -23,151 +23,17 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } -float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) -{ - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); -} - -float distance(ESM::Pathgrid::Point point,float x,float y,float z) -{ - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); -} - -float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) -{ - return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); -} - -int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) -{ - if(!grid) return -1; - if(grid->mPoints.empty()) return -1; - - float m = distance(grid->mPoints[0],x,y,z); - int i0 = 0; - - for(unsigned int i=1; imPoints.size();++i) - { - if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); - i0 = i; - } - } - return i0; -} - float sgn(float a) { if(a>0) return 1.; else return -1.; } -float getZAngle(float dX,float dY) -{ - float h = sqrt(dX*dX+dY*dY); - return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); -} - -typedef boost::adjacency_list,boost::property > PathGridGraph; -typedef boost::property_map::type WeightMap; -typedef PathGridGraph::vertex_descriptor PointID; -typedef PathGridGraph::edge_descriptor PointConnectionID; - -struct found_path {}; - -class goalVisited : public boost::default_astar_visitor -{ -public: - goalVisited(PointID goal) : mGoal(goal) {} - - void examine_vertex(PointID u, const PathGridGraph g) - { - if(u == mGoal) - throw found_path(); - } -private: - PointID mGoal; -}; - -class DistanceHeuristic : public boost::astar_heuristic -{ -public: - DistanceHeuristic(const PathGridGraph & l, PointID goal) - : mGraph(l), mGoal(goal) {} - - float operator()(PointID u) - { - const ESM::Pathgrid::Point & U = mGraph[u]; - const ESM::Pathgrid::Point & V = mGraph[mGoal]; - float dx = U.mX - V.mX; - float dy = U.mY - V.mY; - float dz = U.mZ - V.mZ; - return sqrt(dx * dx + dy * dy + dz * dz); - } -private: - const PathGridGraph & mGraph; - PointID mGoal; -}; - -std::list getPath(PointID start,PointID end,PathGridGraph graph){ - std::vector p(boost::num_vertices(graph)); - std::vector d(boost::num_vertices(graph)); - std::list shortest_path; - - try { - boost::astar_search - ( - graph, - start, - DistanceHeuristic(graph,end), - boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); - - } catch(found_path fg) { - for(PointID v = end;; v = p[v]) { - shortest_path.push_front(graph[v]); - if(p[v] == v) - break; - } - } - return shortest_path; -} - -PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) -{ - PathGridGraph graph; - - for(unsigned int i = 0;imPoints.size();++i) - { - PointID pID = boost::add_vertex(graph); - graph[pID].mX = pathgrid->mPoints[i].mX + xCell; - graph[pID].mY = pathgrid->mPoints[i].mY + yCell; - graph[pID].mZ = pathgrid->mPoints[i].mZ; - } - - for(unsigned int i = 0;imEdges.size();++i) - { - PointID u = pathgrid->mEdges[i].mV0; - PointID v = pathgrid->mEdges[i].mV1; - - PointConnectionID edge; - bool done; - boost::tie(edge,done) = boost::add_edge(u,v,graph); - WeightMap weightmap = boost::get(boost::edge_weight, graph); - weightmap[edge] = distance(graph[u],graph[v]); - - } - - return graph; -} - bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; @@ -193,7 +59,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } } - if(!isPathConstructed ||cellChange) + if(!mPathFinder.mIsPathConstructed ||cellChange) { cellX = actor.getCell()->mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; @@ -205,43 +71,26 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; } - int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); - int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); - - if(start != -1 && end != -1) - { - PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); - mPath = getPath(start,end,graph); - } - ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; dest.mZ = mZ; - mPath.push_back(dest); - isPathConstructed = true; + + ESM::Pathgrid::Point start; + dest.mX = pos.pos[0]; + dest.mY = pos.pos[1]; + dest.mZ = pos.pos[2]; + + mPathFinder.findPath(start,dest,pathgrid,xCell,yCell); } - if(mPath.empty()) + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } - ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distanceZCorrected(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) - { - mPath.pop_front(); - if(mPath.empty()) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } - nextPoint = *mPath.begin(); - } - - float dX = nextPoint.mX - pos.pos[0]; - float dY = nextPoint.mY - pos.pos[1]; - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; return false; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index ef2359ba9..52b41850f 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -2,8 +2,7 @@ #define GAME_MWMECHANICS_AITRAVEL_H #include "aipackage.hpp" -#include -#include +#include "pathfinding.hpp" namespace MWMechanics { @@ -26,8 +25,9 @@ namespace MWMechanics int cellX; int cellY; - bool isPathConstructed; - std::list mPath; + //bool isPathConstructed; + //std::list mPath; + PathFinder mPathFinder; }; } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp new file mode 100644 index 000000000..9b76082b4 --- /dev/null +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -0,0 +1,201 @@ +#include "pathfinding.hpp" +#include +#include +#include "boost/tuple/tuple.hpp" +#include "OgreMath.h" + +namespace MWMechanics +{ + + //helpers functions + float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) + { + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); + } + + float distance(ESM::Pathgrid::Point point,float x,float y,float z) + { + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); + } + + float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) + { + return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); + } + + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } + + int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) + { + if(!grid) return -1; + if(grid->mPoints.empty()) return -1; + + float m = distance(grid->mPoints[0],x,y,z); + int i0 = 0; + + for(unsigned int i=1; imPoints.size();++i) + { + if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); + i0 = i; + } + } + return i0; + } + + typedef boost::adjacency_list,boost::property > PathGridGraph; + typedef boost::property_map::type WeightMap; + typedef PathGridGraph::vertex_descriptor PointID; + typedef PathGridGraph::edge_descriptor PointConnectionID; + + struct found_path {}; + + class goalVisited : public boost::default_astar_visitor + { + public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } + private: + PointID mGoal; + }; + + class DistanceHeuristic : public boost::astar_heuristic + { + public: + DistanceHeuristic(const PathGridGraph & l, PointID goal) + : mGraph(l), mGoal(goal) {} + + float operator()(PointID u) + { + const ESM::Pathgrid::Point & U = mGraph[u]; + const ESM::Pathgrid::Point & V = mGraph[mGoal]; + float dx = U.mX - V.mX; + float dy = U.mY - V.mY; + float dz = U.mZ - V.mZ; + return sqrt(dx * dx + dy * dy + dz * dz); + } + private: + const PathGridGraph & mGraph; + PointID mGoal; + }; + + PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) + { + PathGridGraph graph; + + for(unsigned int i = 0;imPoints.size();++i) + { + PointID pID = boost::add_vertex(graph); + graph[pID].mX = pathgrid->mPoints[i].mX + xCell; + graph[pID].mY = pathgrid->mPoints[i].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[i].mZ; + } + + for(unsigned int i = 0;imEdges.size();++i) + { + PointID u = pathgrid->mEdges[i].mV0; + PointID v = pathgrid->mEdges[i].mV1; + + PointConnectionID edge; + bool done; + boost::tie(edge,done) = boost::add_edge(u,v,graph); + WeightMap weightmap = boost::get(boost::edge_weight, graph); + weightmap[edge] = distance(graph[u],graph[v]); + + } + + return graph; + } + + std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::vector p(boost::num_vertices(graph)); + std::vector d(boost::num_vertices(graph)); + std::list shortest_path; + + try { + boost::astar_search + ( + graph, + start, + DistanceHeuristic(graph,end), + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) + ); + + } catch(found_path fg) { + for(PointID v = end;; v = p[v]) { + shortest_path.push_front(graph[v]); + if(p[v] == v) + break; + } + } + return shortest_path; + } + + //end of helpers functions + + PathFinder::PathFinder() + { + mIsPathConstructed = false; + } + + std::list PathFinder::findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell,float yCell) + { + int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); + int end = getClosestPoint(pathGrid,endPoint.mX - xCell,endPoint.mY - yCell,endPoint.mZ); + + if(start != -1 && end != -1) + { + PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); + mPath = getPath(start,end,graph); + } + + mPath.push_back(endPoint); + mIsPathConstructed = true; + + return mPath; + } + + float PathFinder::getZAngleToNext(float x,float y,float z) + { + if(mPath.empty()) + { + return 0;/// shouldn't happen! + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + float dX = nextPoint.mX - x; + float dY = nextPoint.mY - y; + float h = sqrt(dX*dX+dY*dY); + return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); + } + + bool PathFinder::checkIfNextPointReached(float x,float y,float z) + { + if(mPath.empty()) + { + return true; + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + if(distanceZCorrected(nextPoint,x,y,z) < 20) + { + mPath.pop_front(); + if(mPath.empty()) + { + return true; + } + nextPoint = *mPath.begin(); + } + return false; + } +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp new file mode 100644 index 000000000..200b19125 --- /dev/null +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_MWMECHANICS_PATHFINDING_H +#define GAME_MWMECHANICS_PATHFINDING_H + +#include +#include + +namespace MWMechanics +{ + class PathFinder + { + public: + PathFinder(); + + std::list findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); + + bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. + float getZAngleToNext(float x,float y,float z); + + + std::list mPath; + bool mIsPathConstructed; + }; +} + +#endif \ No newline at end of file From d29a42dcbe37b968827b7648eab6ce8f345bbf66 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 31 Mar 2013 23:18:23 +0200 Subject: [PATCH 050/817] Fixed enchanting mechanics --- apps/openmw/mwclass/armor.cpp | 4 ++-- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 4 ++-- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 4 ++-- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 ++-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 12 +++++++++--- apps/openmw/mwmechanics/enchanting.cpp | 21 +++++++++++---------- apps/openmw/mwmechanics/enchanting.hpp | 4 +++- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 13 files changed, 37 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 281dd1f42..b94c270d5 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -274,7 +274,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -285,7 +285,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 0c32015a3..65f49abb7 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 644561e52..85b006160 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -147,7 +147,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -159,7 +159,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index c17d4255b..29e3de036 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 8f29a2084..d65376898 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -221,7 +221,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -232,7 +232,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 4457e79fb..c3ef22f11 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 894b38acc..ed2a095e3 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -367,7 +367,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -378,7 +378,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 533f32f59..4774bb50b 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ namespace MWClass virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 7d5d1411f..0f3b8b7cb 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -86,10 +86,16 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(actor); - mPtr = actor; + /*Now there's no need to use other enchanters, player is the enchanter here, + even if the enchanted object is created by NPC. Could be changed later, probably + with some price formulas */ + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(player); + + mPtr = player; startEditing (); } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 3590ae0f3..ba4e46de7 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -20,6 +20,7 @@ namespace MWMechanics { mObjectType = mOldItemPtr.getTypeName(); mOldItemId = mOldItemPtr.getCellRef().mRefID; + mOldItemCount = mOldItemPtr.getRefData().getCount(); } else { @@ -50,7 +51,8 @@ namespace MWMechanics int Enchanting::create() { - mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + mEnchantment.mData.mCharge = getGemCharge(); + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { @@ -60,9 +62,6 @@ namespace MWMechanics MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } - mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); - - mEnchantment.mData.mCharge = getGemCharge(); if(mEnchantType==3) { mEnchantment.mData.mCharge=0; @@ -70,15 +69,17 @@ namespace MWMechanics mEnchantment.mData.mType = mEnchantType; mEnchantment.mData.mCost = getEnchantCost(); mEnchantment.mEffects = mEffectList; + const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); - std::string newobjId = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + + mOldItemPtr.getRefData().setCount(1); + + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); + ref.getPtr().getRefData().setCount (mOldItemCount-1); + MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobjId); - MWWorld::Ptr newobjPtr = ref.getPtr(); - MWWorld::Ptr result = mOldItemPtr; - result.mPtr = newobjPtr.mPtr; - MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (result); return 1; } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index fffa2c5b2..1a7dde708 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -13,7 +13,7 @@ namespace MWMechanics MWWorld::Ptr mOldItemPtr; MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mEnchanter; - const MWWorld::Ptr *mNewItemPtr; + int mEnchantType; bool mSelfEnchanting; @@ -24,6 +24,8 @@ namespace MWMechanics std::string mNewItemName; std::string mObjectType; std::string mOldItemId; + int mOldItemCount; + public: Enchanting(); void setEnchanter(MWWorld::Ptr enchanter); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 876328641..9a83063c0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -246,7 +246,7 @@ namespace MWWorld return ""; } - std::string Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 012a03bf6..2f010eb3d 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -234,7 +234,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; From 10d04c928c894d512e999b52e8cea77e8c01eea7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 15:12:10 -0700 Subject: [PATCH 051/817] Use the object's class to check if it's an actor --- .../mwmechanics/mechanicsmanagerimp.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 32fa58980..0af7a4665 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -178,10 +178,10 @@ namespace MWMechanics void MechanicsManager::add(const MWWorld::Ptr& ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.addActivator(ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.addActor(ptr); + else + mActivators.addActivator(ptr); } void MechanicsManager::remove(const MWWorld::Ptr& ptr) @@ -194,10 +194,10 @@ namespace MWMechanics void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.updateActivator(old, ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.updateActor(old, ptr); + else + mActivators.updateActivator(old, ptr); } @@ -656,17 +656,17 @@ namespace MWMechanics void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.playAnimationGroup(ptr, groupName, mode, number); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); + else + mActivators.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.skipAnimation(ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.skipAnimation(ptr); + else + mActivators.skipAnimation(ptr); } } From 04aeb3dd07f53f4cb3484287f5a73399de78ad63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 15:29:41 -0700 Subject: [PATCH 052/817] Rename Mechanics' Activators to Objects --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/activators.cpp | 81 ------------------- apps/openmw/mwmechanics/activators.hpp | 45 ----------- .../mwmechanics/mechanicsmanagerimp.cpp | 14 ++-- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +- apps/openmw/mwmechanics/objects.cpp | 81 +++++++++++++++++++ apps/openmw/mwmechanics/objects.hpp | 45 +++++++++++ 7 files changed, 136 insertions(+), 136 deletions(-) delete mode 100644 apps/openmw/mwmechanics/activators.cpp delete mode 100644 apps/openmw/mwmechanics/activators.hpp create mode 100644 apps/openmw/mwmechanics/objects.cpp create mode 100644 apps/openmw/mwmechanics/objects.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index da8d47439..beb0b9aad 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -63,7 +63,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators + mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate repair enchanting ) diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp deleted file mode 100644 index cbc380299..000000000 --- a/apps/openmw/mwmechanics/activators.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "activators.hpp" - -#include - -#include "movement.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -namespace MWMechanics -{ - -Activators::Activators() -{ -} - -void Activators::addActivator(const MWWorld::Ptr& ptr) -{ - MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if(anim != NULL) - mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); -} - -void Activators::removeActivator (const MWWorld::Ptr& ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - mActivators.erase(iter); -} - -void Activators::updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(old); - if(iter != mActivators.end()) - { - CharacterController ctrl = iter->second; - mActivators.erase(iter); - - ctrl.updatePtr(ptr); - mActivators.insert(std::make_pair(ptr, ctrl)); - } -} - -void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) -{ - PtrControllerMap::iterator iter = mActivators.begin(); - while(iter != mActivators.end()) - { - if(iter->first.getCell()==cellStore) - mActivators.erase(iter++); - else - ++iter; - } -} - -void Activators::update(float duration, bool paused) -{ - if(!paused) - { - for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) - { - Movement movement; - iter->second.update(duration, movement); - } - } -} - -void Activators::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - iter->second.playGroup(groupName, mode, number); -} -void Activators::skipAnimation(const MWWorld::Ptr& ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - iter->second.skipAnim(); -} - -} diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp deleted file mode 100644 index 137674a57..000000000 --- a/apps/openmw/mwmechanics/activators.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATRS_H - -#include -#include - -#include "character.hpp" - -namespace MWWorld -{ - class Ptr; - class CellStore; -} - -namespace MWMechanics -{ - class Activators - { - typedef std::map PtrControllerMap; - PtrControllerMap mActivators; - - public: - Activators(); - - void addActivator (const MWWorld::Ptr& ptr); - ///< Register an animated activator - - void removeActivator (const MWWorld::Ptr& ptr); - ///< Deregister an activator - - void updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); - ///< Updates an activator with a new Ptr - - void dropActivators (const MWWorld::CellStore *cellStore); - ///< Deregister all activators in the given cell. - - void update (float duration, bool paused); - ///< Update activator animations - - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); - void skipAnimation(const MWWorld::Ptr& ptr); - }; -} - -#endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0af7a4665..c8d827921 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -181,7 +181,7 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.addActor(ptr); else - mActivators.addActivator(ptr); + mObjects.addObject(ptr); } void MechanicsManager::remove(const MWWorld::Ptr& ptr) @@ -189,7 +189,7 @@ namespace MWMechanics if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); - mActivators.removeActivator(ptr); + mObjects.removeObject(ptr); } void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) @@ -197,7 +197,7 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.updateActor(old, ptr); else - mActivators.updateActivator(old, ptr); + mObjects.updateObject(old, ptr); } @@ -207,7 +207,7 @@ namespace MWMechanics mWatched = MWWorld::Ptr(); mActors.dropActors(cellStore); - mActivators.dropActivators(cellStore); + mObjects.dropObjects(cellStore); } @@ -319,7 +319,7 @@ namespace MWMechanics } mActors.update(duration, paused); - mActivators.update(duration, paused); + mObjects.update(duration, paused); } void MechanicsManager::restoreDynamicStats() @@ -659,14 +659,14 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); else - mActivators.playAnimationGroup(ptr, groupName, mode, number); + mObjects.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { if(MWWorld::Class::get(ptr).isActor()) mActors.skipAnimation(ptr); else - mActivators.skipAnimation(ptr); + mObjects.skipAnimation(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5ad870571..4b8d42cd3 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,7 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" -#include "activators.hpp" +#include "objects.hpp" #include "actors.hpp" namespace Ogre @@ -31,7 +31,7 @@ namespace MWMechanics bool mClassSelected; bool mRaceSelected; - Activators mActivators; + Objects mObjects; Actors mActors; void buildPlayer(); diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp new file mode 100644 index 000000000..22b996a83 --- /dev/null +++ b/apps/openmw/mwmechanics/objects.cpp @@ -0,0 +1,81 @@ +#include "objects.hpp" + +#include + +#include "movement.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +Objects::Objects() +{ +} + +void Objects::addObject(const MWWorld::Ptr& ptr) +{ + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); + if(anim != NULL) + mObjects.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); +} + +void Objects::removeObject(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + mObjects.erase(iter); +} + +void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(old); + if(iter != mObjects.end()) + { + CharacterController ctrl = iter->second; + mObjects.erase(iter); + + ctrl.updatePtr(ptr); + mObjects.insert(std::make_pair(ptr, ctrl)); + } +} + +void Objects::dropObjects (const MWWorld::Ptr::CellStore *cellStore) +{ + PtrControllerMap::iterator iter = mObjects.begin(); + while(iter != mObjects.end()) + { + if(iter->first.getCell()==cellStore) + mObjects.erase(iter++); + else + ++iter; + } +} + +void Objects::update(float duration, bool paused) +{ + if(!paused) + { + for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter) + { + Movement movement; + iter->second.update(duration, movement); + } + } +} + +void Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + iter->second.playGroup(groupName, mode, number); +} +void Objects::skipAnimation(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + iter->second.skipAnim(); +} + +} diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp new file mode 100644 index 000000000..6f111985c --- /dev/null +++ b/apps/openmw/mwmechanics/objects.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_MWMECHANICS_ACTIVATORS_H +#define GAME_MWMECHANICS_ACTOVATRS_H + +#include +#include + +#include "character.hpp" + +namespace MWWorld +{ + class Ptr; + class CellStore; +} + +namespace MWMechanics +{ + class Objects + { + typedef std::map PtrControllerMap; + PtrControllerMap mObjects; + + public: + Objects(); + + void addObject (const MWWorld::Ptr& ptr); + ///< Register an animated object + + void removeObject (const MWWorld::Ptr& ptr); + ///< Deregister an object + + void updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an object with a new Ptr + + void dropObjects(const MWWorld::CellStore *cellStore); + ///< Deregister all objects in the given cell. + + void update(float duration, bool paused); + ///< Update object animations + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); + }; +} + +#endif From d0703efd69ac5d7e0e8874d19005d2acdf2d9772 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 16:12:02 -0700 Subject: [PATCH 053/817] Another place to check the class' isActor method --- apps/openmw/mwmechanics/character.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7aff2e1d0..02a5aa100 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -111,17 +111,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); getStateInfo(mState, &mCurrentGroup); - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - { - /* Don't accumulate with activators (they don't get moved). */ - mAnimation->setAccumulation(Ogre::Vector3::ZERO); - } - else + if(MWWorld::Class::get(mPtr).isActor()) { /* Accumulate along X/Y only for now, until we can figure out how we should * handle knockout and death which moves the character down. */ mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); } + else + { + /* Don't accumulate with non-actors. */ + mAnimation->setAccumulation(Ogre::Vector3(0.0f)); + } if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", "stop", loop); } From f976eb5bd8f3a083f54adde1dab4726a923a9ad5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 17:31:52 -0700 Subject: [PATCH 054/817] Improve mouselook scaling --- apps/openmw/mwinput/inputmanagerimp.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e514638bb..74d581b81 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -521,11 +521,13 @@ namespace MWInput { resetIdleTime(); - float x = arg.state.X.rel * mCameraSensitivity * 0.2f; - float y = arg.state.Y.rel * mCameraSensitivity * 0.2f * (mInvertY ? -1 : 1) * mUIYMultiplier; + float x = arg.state.X.rel * (1.0f/256.0f) * mCameraSensitivity; + float y = arg.state.Y.rel * (1.0f/256.0f) * mCameraSensitivity * mCameraYMultiplier * (mInvertY ? -1 : 1); + float scale = MWBase::Environment::get().getFrameDuration(); + if(scale <= 0.0f) scale = 1.0f; - mPlayer.setYaw(x); - mPlayer.setPitch(-y); + mPlayer.setYaw(x/scale); + mPlayer.setPitch(-y/scale); if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); From 26db983599daee021e2608cf37eba34254f75892 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 1 Apr 2013 10:46:08 +0200 Subject: [PATCH 055/817] minor fix --- apps/openmw/mwmechanics/objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 6f111985c..3a2e51644 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -1,5 +1,5 @@ #ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATRS_H +#define GAME_MWMECHANICS_ACTOVATORS_H #include #include From 47cc945ef47e646e29a2f49d997ec8b0ba274fd4 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 12:38:13 +0000 Subject: [PATCH 056/817] more refactoring --- apps/openmw/mwmechanics/aitravel.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 17 ++++++++++++----- apps/openmw/mwmechanics/pathfinding.hpp | 5 ++++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index df6a38bb0..b1a4cd0a6 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -59,7 +59,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } } - if(!mPathFinder.mIsPathConstructed ||cellChange) + if(!mPathFinder.isPathConstructed() ||cellChange) { cellX = actor.getCell()->mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; @@ -81,7 +81,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) dest.mY = pos.pos[1]; dest.mZ = pos.pos[2]; - mPathFinder.findPath(start,dest,pathgrid,xCell,yCell); + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9b76082b4..fdac50dda 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -118,7 +118,7 @@ namespace MWMechanics return graph; } - std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::list findPath(PointID start,PointID end,PathGridGraph graph){ std::vector p(boost::num_vertices(graph)); std::vector d(boost::num_vertices(graph)); std::list shortest_path; @@ -149,7 +149,7 @@ namespace MWMechanics mIsPathConstructed = false; } - std::list PathFinder::findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell,float yCell) { int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); @@ -158,13 +158,11 @@ namespace MWMechanics if(start != -1 && end != -1) { PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); - mPath = getPath(start,end,graph); + mPath = findPath(start,end,graph); } mPath.push_back(endPoint); mIsPathConstructed = true; - - return mPath; } float PathFinder::getZAngleToNext(float x,float y,float z) @@ -198,4 +196,13 @@ namespace MWMechanics } return false; } + + std::list PathFinder::getPath() + { + return mPath; + } + bool PathFinder::isPathConstructed() + { + return mIsPathConstructed; + } } \ No newline at end of file diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 200b19125..b1bbab37a 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -11,13 +11,16 @@ namespace MWMechanics public: PathFinder(); - std::list findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. float getZAngleToNext(float x,float y,float z); + std::list getPath(); + bool isPathConstructed(); + private: std::list mPath; bool mIsPathConstructed; }; From 1bff6ed872f9deb860682fae7e398c8778433292 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 1 Apr 2013 17:12:47 +0200 Subject: [PATCH 057/817] Enchaning values import, fixed constness --- apps/openmw/mwmechanics/enchanting.cpp | 46 ++++++++++++++------------ apps/openmw/mwmechanics/enchanting.hpp | 22 ++++++------ 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index ba4e46de7..d86f7c151 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -29,7 +29,7 @@ namespace MWMechanics } } - void Enchanting::setNewItemName(std::string s) + void Enchanting::setNewItemName(const std::string& s) { mNewItemName=s; } @@ -39,7 +39,7 @@ namespace MWMechanics mEffectList=effectList; } - int Enchanting::getEnchantType() + int Enchanting::getEnchantType() const { return mEnchantType; } @@ -49,30 +49,31 @@ namespace MWMechanics mSoulGemPtr=soulGem; } - int Enchanting::create() + bool Enchanting::create() { - mEnchantment.mData.mCharge = getGemCharge(); + ESM::Enchantment enchantment; + enchantment.mData.mCharge = getGemCharge(); mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { if(getEnchantChance() (RAND_MAX)*100) - return 0; + return false; MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } if(mEnchantType==3) { - mEnchantment.mData.mCharge=0; + enchantment.mData.mCharge=0; } - mEnchantment.mData.mType = mEnchantType; - mEnchantment.mData.mCost = getEnchantCost(); - mEnchantment.mEffects = mEffectList; + enchantment.mData.mType = mEnchantType; + enchantment.mData.mCost = getEnchantCost(); + enchantment.mEffects = mEffectList; - const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); + const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment); - MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName); mOldItemPtr.getRefData().setCount(1); @@ -80,7 +81,7 @@ namespace MWMechanics ref.getPtr().getRefData().setCount (mOldItemCount-1); MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - return 1; + return true; } void Enchanting::nextEnchantType() @@ -93,12 +94,13 @@ namespace MWMechanics } if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) { + int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); switch(mEnchantType) { case 1: mEnchantType = 2; case 3: - if(getGemCharge()<400) + if(getGemCharge()getStore(); float cost = 0; @@ -138,7 +140,8 @@ namespace MWMechanics if(mEnchantType==3) { - cost1 *= 100; + int constDurationMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantDurationMult")->getFloat(); + cost1 *= constDurationMultipler; cost2 *= 2; } if(effect->mData.mFlags & ESM::MagicEffect::CastTarget) @@ -152,7 +155,7 @@ namespace MWMechanics } return cost; } - int Enchanting::getGemCharge() + int Enchanting::getGemCharge() const { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); if(soulEmpty()) @@ -163,20 +166,20 @@ namespace MWMechanics return soul->mData.mSoul; } - int Enchanting::getMaxEnchantValue() + int Enchanting::getMaxEnchantValue() const { if (itemEmpty()) return 0; return MWWorld::Class::get(mOldItemPtr).getEnchantmentPoints(mOldItemPtr); } - bool Enchanting::soulEmpty() + bool Enchanting::soulEmpty() const { if (mSoulGemPtr.isEmpty()) return true; return false; } - bool Enchanting::itemEmpty() + bool Enchanting::itemEmpty() const { if(mOldItemPtr.isEmpty()) return true; @@ -193,7 +196,7 @@ namespace MWMechanics mEnchanter = enchanter; } - float Enchanting::getEnchantChance() + float Enchanting::getEnchantChance() const { /* Formula from http://www.uesp.net/wiki/Morrowind:Enchant @@ -208,7 +211,8 @@ namespace MWMechanics float chance2 = 2.5 * getEnchantCost(); if(mEnchantType==3) { - chance2 *= 2; + float constantChance = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantChanceMult")->getFloat(); + chance2 /= constantChance; } return (chance1-chance2); } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 1a7dde708..c951ae825 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -9,7 +9,6 @@ namespace MWMechanics { class Enchanting { - MWWorld::Ptr mOldItemPtr; MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mEnchanter; @@ -19,7 +18,6 @@ namespace MWMechanics bool mSelfEnchanting; ESM::EffectList mEffectList; - ESM::Enchantment mEnchantment; std::string mNewItemName; std::string mObjectType; @@ -31,18 +29,18 @@ namespace MWMechanics void setEnchanter(MWWorld::Ptr enchanter); void setSelfEnchanting(bool selfEnchanting); void setOldItem(MWWorld::Ptr oldItem); - void setNewItemName(std::string s); + void setNewItemName(const std::string& s); void setEffect(ESM::EffectList effectList); void setSoulGem(MWWorld::Ptr soulGem); - int create(); - void nextEnchantType(); - int getEnchantType(); - int getEnchantCost(); - int getMaxEnchantValue(); - int getGemCharge(); - float getEnchantChance(); - bool soulEmpty(); - bool itemEmpty(); + bool create(); //Return true if created, false if failed. + void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) + int getEnchantType() const; + int getEnchantCost() const; + int getMaxEnchantValue() const; + int getGemCharge() const; + float getEnchantChance() const; + bool soulEmpty() const; //Return true if empty + bool itemEmpty() const; //Return true if empty }; } #endif From 9dbd024076efabe5e3a109e359495bb9f7c75cee Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 1 Apr 2013 17:30:54 +0200 Subject: [PATCH 058/817] another minor fix --- apps/openmw/mwmechanics/objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 3a2e51644..7b1185a29 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -1,5 +1,5 @@ #ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATORS_H +#define GAME_MWMECHANICS_ACTIVATORS_H #include #include From 2be9405c96056fc6a12b2c5d4d048e0d74ca3d6d Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 15:44:08 +0000 Subject: [PATCH 059/817] the sgn function is no longer in the global namespace --- apps/openmw/mwmechanics/aitravel.cpp | 157 ++++++++++++++------------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b1a4cd0a6..4aca5f3d4 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,92 +13,95 @@ #include #include "boost/tuple/tuple.hpp" -MWMechanics::AiTravel::AiTravel(float x, float y, float z) - : mX(x),mY(y),mZ(z),mPathFinder() +namespace MWMechanics { -} -MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const -{ - return new AiTravel(*this); -} - -float sgn(float a) -{ - if(a>0) return 1.; - else return -1.; -} - -bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) -{ - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - ESM::Position pos = actor.getRefData().getPosition(); - bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + AiTravel::AiTravel(float x, float y, float z) + : mX(x),mY(y),mZ(z),mPathFinder() { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + } + + AiTravel * AiTravel::clone() const + { + return new AiTravel(*this); + } + + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } + + bool AiTravel::execute (const MWWorld::Ptr& actor) + { + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + + if(!mPathFinder.isPathConstructed() ||cellChange) + { + cellX = actor.getCell()->mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; + float xCell = 0; + float yCell = 0; + if (actor.getCell()->mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } + + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + + ESM::Pathgrid::Point start; + dest.mX = pos.pos[0]; + dest.mY = pos.pos[1]; + dest.mZ = pos.pos[2]; + + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); + } + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } + + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + + return false; } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + + int AiTravel::getTypeId() const { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } + return 1; } - if(!mPathFinder.isPathConstructed() ||cellChange) - { - cellX = actor.getCell()->mCell->mData.mX; - cellY = actor.getCell()->mCell->mData.mY; - float xCell = 0; - float yCell = 0; - if (actor.getCell()->mCell->isExterior()) - { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; - } - - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; - - ESM::Pathgrid::Point start; - dest.mX = pos.pos[0]; - dest.mY = pos.pos[1]; - dest.mZ = pos.pos[2]; - - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); - } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } - - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; - - return false; } - -int MWMechanics::AiTravel::getTypeId() const -{ - return 1; -} - - From 20af7d89a2550a9873dd0ab03d5240af25f3b0f7 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 17:30:40 +0000 Subject: [PATCH 060/817] post master-merge fixes. Looks a little odd. --- apps/openmw/mwmechanics/aitravel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 4aca5f3d4..dd769f91c 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -47,7 +47,7 @@ namespace MWMechanics //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } @@ -57,7 +57,7 @@ namespace MWMechanics //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } @@ -88,13 +88,13 @@ namespace MWMechanics } if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; return false; } From 6a33170ca244db400d49651597ce3cc80d753723 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 17:44:06 +0000 Subject: [PATCH 061/817] More bugfix, but I don't like this one. --- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index dd769f91c..25efe8fff 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -26,7 +26,7 @@ namespace MWMechanics return new AiTravel(*this); } - float sgn(float a) + static float sgn(float a) { if(a>0) return 1.; else return -1.; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index fdac50dda..1d98674ef 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -23,7 +23,7 @@ namespace MWMechanics return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); } - float sgn(float a) + static float sgn(float a) { if(a>0) return 1.; else return -1.; From d25c838e1d3c5f9aabfc4c41e1482e835c6c034e Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 11:42:29 +0200 Subject: [PATCH 062/817] Bugfix #646 --- apps/openmw/mwworld/actionequip.cpp | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index afbb505f2..513182a2d 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -108,6 +108,46 @@ namespace MWWorld } + //Disable twohanded when shield equipped, shield when twohanded equipped + if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) + { + invStore.equip(*slot, it); + + if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + } + } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + } + } + // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) { From c71edb613d12e3b46bd4d0e998e054bbcf4cc330 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 12:00:45 +0200 Subject: [PATCH 063/817] added faction table --- apps/opencs/model/world/data.cpp | 16 ++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 3 +++ components/esm/loadfact.cpp | 25 +++++++++++++++++++++++-- components/esm/loadfact.hpp | 3 +++ 9 files changed, 67 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 7b3e66771..825e29a23 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -57,10 +57,15 @@ CSMWorld::Data::Data() mClasses.addColumn (new PlayableColumn); mClasses.addColumn (new DescriptionColumn); + mFactions.addColumn (new StringIdColumn); + mFactions.addColumn (new RecordStateColumn); + mFactions.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); + addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); } CSMWorld::Data::~Data() @@ -99,6 +104,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSkills() return mSkills; } +const CSMWorld::IdCollection& CSMWorld::Data::getFactions() const +{ + return mFactions; +} + +CSMWorld::IdCollection& CSMWorld::Data::getFactions() +{ + return mFactions; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -137,6 +152,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_GMST: mGmsts.load (reader, base); break; case ESM::REC_SKIL: mSkills.load (reader, base); break; case ESM::REC_CLAS: mClasses.load (reader, base); break; + case ESM::REC_FACT: mFactions.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 7baf03259..1e2894774 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -24,6 +25,7 @@ namespace CSMWorld IdCollection mGmsts; IdCollection mSkills; IdCollection mClasses; + IdCollection mFactions; std::vector mModels; std::map mModelIndex; @@ -52,6 +54,10 @@ namespace CSMWorld IdCollection& getSkills(); + const IdCollection& getFactions() const; + + IdCollection& getFactions(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index a85b30c2a..985cab0d4 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -21,6 +21,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -31,6 +32,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 4c4d95654..0190467c4 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -41,7 +41,9 @@ namespace CSMWorld Type_Skills, Type_Skill, Type_Classes, - Type_Class + Type_Class, + Type_Factions, + Type_Faction }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 2ef66593f..3c4bc3b04 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -94,6 +94,10 @@ void CSVDoc::View::setupWorldMenu() connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView())); world->addAction (classes); + QAction *factions = new QAction (tr ("Factions"), this); + connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); + world->addAction (factions); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -262,6 +266,11 @@ void CSVDoc::View::addClassesSubView() addSubView (CSMWorld::UniversalId::Type_Classes); } +void CSVDoc::View::addFactionsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Factions); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index bc8e8fc26..03905430a 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -119,6 +119,8 @@ namespace CSVDoc void addSkillsSubView(); void addClassesSubView(); + + void addFactionsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 5d715ea21..cbfbf6b46 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -20,6 +20,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Classes, new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Factions, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); + // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 6ea66977d..50fb94bbb 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -33,7 +33,7 @@ void Faction::load(ESMReader &esm) void Faction::save(ESMWriter &esm) { esm.writeHNCString("FNAM", mName); - + for (int i = 0; i < 10; i++) { if (mRanks[i].empty()) @@ -43,7 +43,7 @@ void Faction::save(ESMWriter &esm) } esm.writeHNT("FADT", mData, 240); - + for (std::vector::iterator it = mReactions.begin(); it != mReactions.end(); ++it) { esm.writeHNString("ANAM", it->mFaction); @@ -51,4 +51,25 @@ void Faction::save(ESMWriter &esm) } } + void Faction::blank() + { + mName.clear(); + mData.mAttribute1 = mData.mAttribute2 = 0; + mData.mUnknown = -1; + mData.mIsHidden = 0; + + for (int i=0; i<10; ++i) + { + mData.mRankData[i].mAttribute1 = mData.mRankData[i].mAttribute2 = 0; + mData.mRankData[i].mSkill1 = mData.mRankData[i].mSkill2 = 0; + mData.mRankData[i].mFactReaction = 0; + + mRanks[i].clear(); + } + + for (int i=0; i<6; ++i) + mData.mSkillID[i] = 0; + + mReactions.clear(); + } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 49898b1cf..a2ba688c0 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -58,6 +58,9 @@ struct Faction void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From f9f520df34373dc585d7bf695362564a6b7fe3b7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 13:59:45 +0200 Subject: [PATCH 064/817] adjusted faction record to increase consistency with other records --- apps/esmtool/record.cpp | 14 +++++++------- apps/openmw/mwdialogue/filter.cpp | 4 ++-- apps/openmw/mwgui/stats_window.cpp | 6 +++--- apps/openmw/mwmechanics/npcstats.cpp | 2 +- components/esm/loadclas.cpp | 19 +++++++++++++++++++ components/esm/loadclas.hpp | 6 ++++++ components/esm/loadfact.cpp | 21 +++++++++++++++++++-- components/esm/loadfact.hpp | 10 ++++++++-- 8 files changed, 65 insertions(+), 17 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index de3a17510..8f77e4b44 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -679,14 +679,14 @@ void Record::print() std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl; if (mData.mData.mUnknown != -1) std::cout << " Unknown: " << mData.mData.mUnknown << std::endl; - std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute1) - << " (" << mData.mData.mAttribute1 << ")" << std::endl; - std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute2) - << " (" << mData.mData.mAttribute2 << ")" << std::endl; + std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttributes[0]) + << " (" << mData.mData.mAttributes[0] << ")" << std::endl; + std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttributes[1]) + << " (" << mData.mData.mAttributes[1] << ")" << std::endl; for (int i = 0; i != 6; i++) - if (mData.mData.mSkillID[i] != -1) - std::cout << " Skill: " << skillLabel(mData.mData.mSkillID[i]) - << " (" << mData.mData.mSkillID[i] << ")" << std::endl; + if (mData.mData.mSkills[i] != -1) + std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) + << " (" << mData.mData.mSkills[i] << ")" << std::endl; for (int i = 0; i != 10; i++) if (mData.mRanks[i] != "") { diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index f7e952956..ddb15d423 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -569,8 +569,8 @@ bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& ac MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor); - return stats.getAttribute (faction.mData.mAttribute1).getBase()>=faction.mData.mRankData[rank].mAttribute1 && - stats.getAttribute (faction.mData.mAttribute2).getBase()>=faction.mData.mRankData[rank].mAttribute2; + return stats.getAttribute (faction.mData.mAttributes[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && + stats.getAttribute (faction.mData.mAttributes[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; } bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 0fa4127b5..86019fa28 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -500,8 +500,8 @@ void StatsWindow::updateSkillArea() text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute1); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute2); + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttributes[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttributes[1]); assert(attr1 && attr2); text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) @@ -511,7 +511,7 @@ void StatsWindow::updateSkillArea() text += "\n#BF9959"; for (int i=0; i<6; ++i) { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkillID[i]]+"}"; + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; if (i<5) text += ", "; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index b9aee6abf..7216e8fe0 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -334,7 +334,7 @@ bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int std::vector skills; for (int i=0; i<6; ++i) - skills.push_back (static_cast (getSkill (faction.mData.mSkillID[i]).getModified())); + skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getModified())); std::sort (skills.begin(), skills.end()); diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index d9f367fd6..bdc461462 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -1,5 +1,7 @@ #include "loadclas.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" @@ -18,6 +20,23 @@ const char *Class::sGmstSpecializationIds[3] = { "sSpecializationStealth" }; + + int& Class::CLDTstruct::getSkill (int index, bool major) + { + if (index<0 || index>=5) + throw std::logic_error ("skill index out of range"); + + return mSkills[index][major ? 1 : 0]; + } + + int Class::CLDTstruct::getSkill (int index, bool major) const + { + if (index<0 || index>=5) + throw std::logic_error ("skill index out of range"); + + return mSkills[index][major ? 1 : 0]; + } + void Class::load(ESMReader &esm) { mName = esm.getHNString("FNAM"); diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index ac596af32..4f85e6ee8 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -58,6 +58,12 @@ struct Class // I have no idea how to autocalculate these items... int mCalc; + + int& getSkill (int index, bool major); + ///< Throws an exception for invalid values of \a index. + + int getSkill (int index, bool major) const; + ///< Throws an exception for invalid values of \a index. }; // 60 bytes std::string mId, mName, mDescription; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 50fb94bbb..12a76f1ad 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -1,10 +1,27 @@ #include "loadfact.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" namespace ESM { + int& Faction::FADTstruct::getSkill (int index, bool ignored) + { + if (index<0 || index>=6) + throw std::logic_error ("skill index out of range"); + + return mSkills[index]; + } + + int Faction::FADTstruct::getSkill (int index, bool ignored) const + { + if (index<0 || index>=6) + throw std::logic_error ("skill index out of range"); + + return mSkills[index]; + } void Faction::load(ESMReader &esm) { @@ -54,7 +71,7 @@ void Faction::save(ESMWriter &esm) void Faction::blank() { mName.clear(); - mData.mAttribute1 = mData.mAttribute2 = 0; + mData.mAttributes[0] = mData.mAttributes[1] = 0; mData.mUnknown = -1; mData.mIsHidden = 0; @@ -68,7 +85,7 @@ void Faction::save(ESMWriter &esm) } for (int i=0; i<6; ++i) - mData.mSkillID[i] = 0; + mData.mSkills[i] = 0; mReactions.clear(); } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index a2ba688c0..edc4640bb 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -34,13 +34,19 @@ struct Faction struct FADTstruct { // Which attributes we like - int mAttribute1, mAttribute2; + int mAttributes[2]; RankData mRankData[10]; - int mSkillID[6]; // IDs of skills this faction require + int mSkills[6]; // IDs of skills this faction require int mUnknown; // Always -1? int mIsHidden; // 1 - hidden from player + + int& getSkill (int index, bool ignored = false); + ///< Throws an exception for invalid values of \a index. + + int getSkill (int index, bool ignored = false) const; + ///< Throws an exception for invalid values of \a index. }; // 240 bytes FADTstruct mData; From ec6bdbeb40dd3641233ac5e22b4557ee795affe0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 14:04:13 +0200 Subject: [PATCH 065/817] added skill columns to faction table --- apps/opencs/model/world/columns.hpp | 8 ++++---- apps/opencs/model/world/data.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index cbcddd972..9345df0d2 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -347,15 +347,15 @@ namespace CSMWorld int mIndex; bool mMajor; - SkillsColumn (int index, bool major) - : Column ((major ? "Major Skill #" : "Minor Skill #")+ + SkillsColumn (int index, bool typePrefix = false, bool major = false) + : Column ((typePrefix ? (major ? "Major Skill #" : "Minor Skill #") : "Skill #")+ boost::lexical_cast (index), ColumnBase::Display_String), mIndex (index), mMajor (major) {} virtual QVariant get (const Record& record) const { - int skill = record.get().mData.mSkills[mIndex][mMajor ? 1 : 0]; + int skill = record.get().mData.getSkill (mIndex, mMajor); return QString::fromUtf8 (ESM::Skill::indexToId (skill).c_str()); } @@ -373,7 +373,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - record2.mData.mSkills[mIndex][mMajor ? 1 : 0] = index; + record2.mData.getSkill (mIndex, mMajor) = index; record.setModified (record2); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 825e29a23..23a1eb91b 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -51,15 +51,17 @@ CSMWorld::Data::Data() mClasses.addColumn (new AttributesColumn (1)); mClasses.addColumn (new SpecialisationColumn); for (int i=0; i<5; ++i) - mClasses.addColumn (new SkillsColumn (i, true)); + mClasses.addColumn (new SkillsColumn (i, true, true)); for (int i=0; i<5; ++i) - mClasses.addColumn (new SkillsColumn (i, false)); + mClasses.addColumn (new SkillsColumn (i, true, false)); mClasses.addColumn (new PlayableColumn); mClasses.addColumn (new DescriptionColumn); mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + for (int i=0; i<6; ++i) + mFactions.addColumn (new SkillsColumn (i)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 900c2cfa81b629a74fcb3ce112fbbf1578217c3a Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 14:08:59 +0200 Subject: [PATCH 066/817] Minor bugfix #646 change --- apps/openmw/mwworld/actionequip.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 513182a2d..9a44a9979 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -111,8 +111,6 @@ namespace MWWorld //Disable twohanded when shield equipped, shield when twohanded equipped if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - invStore.equip(*slot, it); - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) { if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || From 384c88182dfa5ab54e215bafa99edc8cfed6a867 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 14:15:22 +0200 Subject: [PATCH 067/817] dealing with unset attribute fields --- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/world/enumdelegate.cpp | 5 ++++- apps/opencs/view/world/enumdelegate.hpp | 3 ++- components/esm/loadskil.cpp | 15 +++++++++------ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index bc8772894..3be7228b3 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -61,7 +61,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) new CSVWorld::EnumDelegateFactory (sSpecialisations)); mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, - new CSVWorld::EnumDelegateFactory (sAttributes)); + new CSVWorld::EnumDelegateFactory (sAttributes, true)); } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 0dd0a1d59..b1e9f7286 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -92,10 +92,13 @@ void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewIte CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {} -CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names) +CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names, bool allowNone) { assert (names); + if (allowNone) + add (-1, ""); + for (int i=0; names[i]; ++i) add (i, names[i]); } diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index 752ed5be7..58f19ff78 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -47,8 +47,9 @@ namespace CSVWorld EnumDelegateFactory(); - EnumDelegateFactory (const char **names); + EnumDelegateFactory (const char **names, bool allowNone = false); ///< \param names Array of char pointer with a 0-pointer as end mark + /// \param allowNone Use value of -1 for "none selected" (empty string) virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b7259db94..b57645f3b 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -127,15 +127,18 @@ void Skill::save(ESMWriter &esm) { std::ostringstream stream; - stream << "#"; + if (index!=-1) + { + stream << "#"; - if (index<10) - stream << "0"; + if (index<10) + stream << "0"; - stream << index; + stream << index; - if (index>=0 && index=0 && index Date: Tue, 2 Apr 2013 14:20:51 +0200 Subject: [PATCH 068/817] added hidden flag column to faction table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 9345df0d2..dfabaaf2c 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -409,6 +409,31 @@ namespace CSMWorld return true; } }; + + template + struct HiddenColumn : public Column + { + HiddenColumn() : Column ("Hidden", ColumnBase::Display_Boolean) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mIsHidden!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mIsHidden = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 23a1eb91b..13fff7f09 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -60,6 +60,7 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + mFactions.addColumn (new HiddenColumn); for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); From 9d009af2a132823795dc949ed9b030e4a95e7a1e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 15:33:28 +0200 Subject: [PATCH 069/817] simplified code for sub view factory creation --- apps/opencs/view/world/subviews.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index cbfbf6b46..de36594a5 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -8,20 +8,24 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { - manager.add (CSMWorld::UniversalId::Type_Globals, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); - manager.add (CSMWorld::UniversalId::Type_Gmsts, new CSVDoc::SubViewFactoryWithCreateFlag (false)); manager.add (CSMWorld::UniversalId::Type_Skills, new CSVDoc::SubViewFactoryWithCreateFlag (false)); - manager.add (CSMWorld::UniversalId::Type_Classes, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); + static const CSMWorld::UniversalId::Type sTableTypes[] = + { + CSMWorld::UniversalId::Type_Globals, + CSMWorld::UniversalId::Type_Classes, + CSMWorld::UniversalId::Type_Factions, + + CSMWorld::UniversalId::Type_None // end marker + }; + + for (int i=0; sTableTypes[i]!=CSMWorld::UniversalId::Type_None; ++i) + manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreateFlag (true)); - manager.add (CSMWorld::UniversalId::Type_Factions, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); From 676a92e2e0157abe29fd898531b0c63610db0466 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 15:47:25 +0200 Subject: [PATCH 070/817] moved Verify function from World menu to File menu --- apps/opencs/view/doc/view.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3c4bc3b04..83b333c04 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -41,6 +41,10 @@ void CSVDoc::View::setupFileMenu() connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); + mVerify = new QAction (tr ("&Verify"), this); + connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); + file->addAction (mVerify); + QAction *close = new QAction (tr ("&Close"), this); connect (close, SIGNAL (triggered()), this, SLOT (close())); file->addAction(close); @@ -97,10 +101,6 @@ void CSVDoc::View::setupWorldMenu() QAction *factions = new QAction (tr ("Factions"), this); connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); world->addAction (factions); - - mVerify = new QAction (tr ("&Verify"), this); - connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); - world->addAction (mVerify); } void CSVDoc::View::setupUi() From 369cf0b4cafac002e0a0338163b95a29630f2b51 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 20:46:48 +0200 Subject: [PATCH 071/817] Enchanting price mechanics --- apps/openmw/mwgui/enchantingdialog.cpp | 27 ++++++++---------- apps/openmw/mwmechanics/enchanting.cpp | 38 +++++++++++++++++++++++++- apps/openmw/mwmechanics/enchanting.hpp | 2 ++ 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 0f3b8b7cb..1ed80127d 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -63,6 +63,8 @@ namespace MWGui mCastCost->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost())); + mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); + switch(mEnchanting.getEnchantType()) { case 0: @@ -86,16 +88,10 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { - - /*Now there's no need to use other enchanters, player is the enchanter here, - even if the enchanted object is created by NPC. Could be changed later, probably - with some price formulas */ - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(player); + mEnchanting.setEnchanter(actor); - mPtr = player; + mPtr = actor; startEditing (); } @@ -103,13 +99,14 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Ptr gem = soulgem; mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); mPtr = player; - startEditing(); + mEnchanting.setSoulGem(gem); } void EnchantingDialog::onReferenceUnavailable () @@ -252,12 +249,6 @@ namespace MWGui return; } - if (boost::lexical_cast(mPrice->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) - { - mWindowManager.messageBox ("#{sNotifyMessage18}"); - return; - } - if (mEnchanting.soulEmpty()) { mWindowManager.messageBox ("#{sNotifyMessage52}"); @@ -279,6 +270,12 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); + if (mEnchanting.getEnchantPrice() > mWindowManager.getInventoryWindow()->getPlayerGold()) + { + mWindowManager.messageBox ("#{sNotifyMessage18}"); + return; + } + int result = mEnchanting.create(); if(result==1) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d86f7c151..a2f85fb0c 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -3,6 +3,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" #include "npcstats.hpp" @@ -79,7 +80,10 @@ namespace MWMechanics MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); ref.getPtr().getRefData().setCount (mOldItemCount-1); - MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); + payForEnchantment(); return true; } @@ -126,6 +130,8 @@ namespace MWMechanics float cost = 0; std::vector mEffects = mEffectList.mList; int i=mEffects.size(); + if(i<=0) + return 0; /* Formula from http://www.uesp.net/wiki/Morrowind:Enchant @@ -155,6 +161,17 @@ namespace MWMechanics } return cost; } + + int Enchanting::getEnchantPrice() const + { + if(mEnchanter.isEmpty()) + return 0; + + float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->getFloat(); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantCost() * priceMultipler), true); + return price; + } + int Enchanting::getGemCharge() const { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -216,4 +233,23 @@ namespace MWMechanics } return (chance1-chance2); } + + void Enchanting::payForEnchantment() const + { + MWWorld::Ptr gold; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + + for (MWWorld::ContainerStoreIterator it = store.begin(); + it != store.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) + { + gold = *it; + } + } + + gold.getRefData().setCount(gold.getRefData().getCount() - getEnchantPrice()); + } } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index c951ae825..d8a6342ac 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -36,11 +36,13 @@ namespace MWMechanics void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) int getEnchantType() const; int getEnchantCost() const; + int getEnchantPrice() const; int getMaxEnchantValue() const; int getGemCharge() const; float getEnchantChance() const; bool soulEmpty() const; //Return true if empty bool itemEmpty() const; //Return true if empty + void payForEnchantment() const; }; } #endif From 98727d2fb6c6ec26a5f8dabe370d9714b23d71dd Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 21:32:23 +0200 Subject: [PATCH 072/817] Workaround for launcher compilation problems due to bug in Qt MOC compiler. For details please see: https://forum.openmw.org/viewtopic.php?f=7&t=1451 https://bugreports.qt-project.org/browse/QTBUG-22829 Signed-off-by: Lukasz Gromanowski --- apps/launcher/maindialog.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 7e818a74a..824dff6e8 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -2,9 +2,9 @@ #define MAINDIALOG_H #include - +#ifndef Q_MOC_RUN #include - +#endif #include "settings/gamesettings.hpp" #include "settings/graphicssettings.hpp" #include "settings/launchersettings.hpp" From 7b7d3353a66fc30e6282c6d3931d012abbfa029e Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 22:23:38 +0200 Subject: [PATCH 073/817] Exception for enchanting with Azura Star --- apps/openmw/mwmechanics/enchanting.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index a2f85fb0c..45db667d2 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -54,7 +54,12 @@ namespace MWMechanics { ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); - mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + + //Exception for Azura Star, it's not destroyed after enchanting + if(mSoulGemPtr.get()->mBase->mId=="Misc_SoulGem_Azura") + mSoulGemPtr.getCellRef().mSoul=""; + else + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { From 061fb4c482353633d2610166646a981998307a24 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:15:22 +0200 Subject: [PATCH 074/817] Added simple Travis CI cfg file. Added simple Travis CI configuration file for testing. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..94cf74924 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: cpp +compiler: + - clang + - gcc +before_script: + - mkdir build + - cd build + - cmake .. +branches: + only: + - master + - travis_ci_test +notifications: + recipients: + - lgromanowski+travis.ci@gmail.com + email: + on_success: change + on_failure: always From df8da0486da56835f55ab31e2aa87bfda82a50e0 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:20:59 +0200 Subject: [PATCH 075/817] Small changes in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 94cf74924..f2a9179f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,9 @@ before_script: - mkdir build - cd build - cmake .. +before_install: + - git submodule update --init --recursive +script: make branches: only: - master From cb18cf1eee9ab28ced4347aa880403972ed18dde Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:30:44 +0200 Subject: [PATCH 076/817] Added OpenMW dependencies into .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f2a9179f5..6e3748056 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,10 @@ before_script: - cd build - cmake .. before_install: - - git submodule update --init --recursive + - git submodule update --init --recursive + - sudo apt-add-repository ppa:openmw/deps + - sudo apt-get update -qq + - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make branches: only: From 4f19fb0cdbfa5ac3815f83133cb1d864f371274a Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:38:23 +0200 Subject: [PATCH 077/817] Changes in apt-add-repository line - added echo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6e3748056..cdbabb1a1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_script: - cmake .. before_install: - git submodule update --init --recursive - - sudo apt-add-repository ppa:openmw/deps + - echo -e "\n" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make From f8497895149469720e56c25fc0b9b25e08e3c058 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:41:24 +0200 Subject: [PATCH 078/817] Changes in apt-add-repository line. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cdbabb1a1..3d3ad404c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_script: - cmake .. before_install: - git submodule update --init --recursive - - echo -e "\n" | sudo apt-add-repository ppa:openmw/deps + - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make From df0ee82a3c9f27700ee39ac5175a01fc77912b7a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Apr 2013 23:45:32 +0200 Subject: [PATCH 079/817] Loose files should have priority over BSA resources. This makes texture replacers work. --- apps/openmw/engine.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ce84b8dfe..dad024c98 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -153,20 +153,6 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { - for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) - { - if (mFileCollections.doesExist(*archive)) - { - const std::string archivePath = mFileCollections.getPath(*archive).string(); - std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath); - } - else - { - std::cout << "Archive " << *archive << " not found" << std::endl; - } - } - const Files::PathContainer& dataDirs = mFileCollections.getPaths(); std::string dataDirectory; for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) @@ -175,6 +161,24 @@ void OMW::Engine::loadBSA() std::cout << "Data dir " << dataDirectory << std::endl; Bsa::addDir(dataDirectory, mFSStrict); } + + // BSA resources are put into a separate group. We want loose files to have priority over BSA resources, and this seems + // to be the only way to get Ogre to do just that. + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup ("GroupBSA"); + + for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) + { + if (mFileCollections.doesExist(*archive)) + { + const std::string archivePath = mFileCollections.getPath(*archive).string(); + std::cout << "Adding BSA archive " << archivePath << std::endl; + Bsa::addBSA(archivePath, "GroupBSA"); + } + else + { + std::cout << "Archive " << *archive << " not found" << std::endl; + } + } } // add resources directory From 73b984cc2d01ccca61cd5efeaa51f324060e69d9 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:08:24 +0200 Subject: [PATCH 080/817] Corrected packages names in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3d3ad404c..75fe32299 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev mygui-static-dev script: make branches: only: From c32f4d853e6ca6b9f5f06367ad526f911c034bfb Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:14:26 +0200 Subject: [PATCH 081/817] Another change in packages names in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 75fe32299..a29140b25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev mygui-static-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev script: make branches: only: From c73209c049b4ba2776fb8c11ae91132dba8515a8 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:21:42 +0200 Subject: [PATCH 082/817] Added another part of dependencies, enabled building with static ogre and mygui. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a29140b25..1239f1ed0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,12 @@ compiler: before_script: - mkdir build - cd build - - cmake .. + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev script: make branches: only: From 05a5cb3ae48e00d82488d2d4056a5fd906cde571 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 00:27:29 +0200 Subject: [PATCH 083/817] Improved responsiveness of the inventory window when resizing. --- apps/openmw/engine.cpp | 1 + apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/inventorywindow.cpp | 20 +++++++++++++++----- apps/openmw/mwgui/inventorywindow.hpp | 4 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dad024c98..948a06d47 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -66,6 +66,7 @@ bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) { if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame); + MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame); return true; } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4d66a7742..b271aed18 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -246,6 +246,8 @@ namespace MWBase virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; + virtual void frameStarted(float dt) = 0; + virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1943ff773..aeab5f94a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -37,6 +37,7 @@ namespace MWGui , mLastXSize(0) , mLastYSize(0) , mPreview(MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()) + , mPreviewDirty(true) { static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); @@ -268,6 +269,19 @@ namespace MWGui mTrading = true; } + void InventoryWindow::doRenderUpdate () + { + if (mPreviewDirty) + { + mPreviewDirty = false; + MyGUI::IntSize size = mAvatar->getSize(); + + mPreview.update (size.width, size.height); + mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); + mAvatarImage->setImageTexture("CharacterPreview"); + } + } + void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory @@ -282,11 +296,7 @@ namespace MWGui else mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability - MyGUI::IntSize size = mAvatar->getSize(); - - mPreview.update (size.width, size.height); - mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); - mAvatarImage->setImageTexture("CharacterPreview"); + mPreviewDirty = true; mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + boost::lexical_cast(static_cast(MWWorld::Class::get(mPtr).getArmorRating(mPtr)))); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 95657672d..fceb7ecef 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -16,6 +16,8 @@ namespace MWGui virtual void open(); + void doRenderUpdate(); + /// start trading, disables item drag&drop void startTrade(); @@ -34,6 +36,8 @@ namespace MWGui } protected: + bool mPreviewDirty; + MyGUI::Widget* mAvatar; MyGUI::ImageBox* mAvatarImage; MyGUI::TextBox* mArmorRating; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cf14c1f51..c975b2cdb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1190,3 +1190,8 @@ void WindowManager::showSoulgemDialog(MWWorld::Ptr item) { mSoulgemDialog->show(item); } + +void WindowManager::frameStarted (float dt) +{ + mInventoryWindow->doRenderUpdate (); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7a7adec27..c14c6b2fe 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -238,6 +238,8 @@ namespace MWGui virtual void startRepair(MWWorld::Ptr actor); virtual void startRepairItem(MWWorld::Ptr item); + virtual void frameStarted(float dt); + virtual void showSoulgemDialog (MWWorld::Ptr item); virtual void changePointer (const std::string& name); From 5a1bb21b23b1c68a1ea597ac339396a0a2704aee Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:30:43 +0200 Subject: [PATCH 084/817] Build dependecies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1239f1ed0..80c3a4653 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools script: make branches: only: From 74d519d4057fe9d06c4b3b0fe3d6d1cafb074390 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:35:18 +0200 Subject: [PATCH 085/817] Added libois into build dependencies in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 80c3a4653..51fa23e8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools libois-dev script: make branches: only: From 798ed642030dc059e0ab4d4963061bffb07131b6 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:40:01 +0200 Subject: [PATCH 086/817] Added google-mock and libopenal into build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 51fa23e8e..003a4d801 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools libois-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev script: make branches: only: From 5957a9e037942934b30202b572ed9d8bb0cb4876 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:44:03 +0200 Subject: [PATCH 087/817] Added libxaw7 into dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 003a4d801..4939ad0ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From e7bb3743cc491d00e036791d6f74ccf512d92286 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:58:59 +0200 Subject: [PATCH 088/817] Trying to build with Ogre shared lib . Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4939ad0ec..d31e4afc8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,12 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 + - cmake .. -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From f6f165852dda10d098f2f8daa2ee9081291329fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Apr 2013 21:08:21 -0700 Subject: [PATCH 089/817] Better handle material texture layers --- components/nifogre/ogrenifloader.cpp | 110 ++++++++++++++++----------- 1 file changed, 67 insertions(+), 43 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 5aa5ff80c..b3ab4c016 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -538,16 +538,51 @@ static std::map MaterialMap; static void warn(const std::string &msg) { - std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; } static void fail(const std::string &msg) { - std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; abort(); } +static std::string findTextureName(const std::string &filename) +{ + /* Bethesda at some point converted all their BSA + * textures from tga to dds for increased load speed, but all + * texture file name references were kept as .tga. + */ + static const char path[] = "textures\\"; + + std::string texname = filename; + Misc::StringUtils::toLower(texname); + + if(texname.compare(0, sizeof(path)-1, path) != 0) + texname = path + texname; + + Ogre::String::size_type pos = texname.rfind('.'); + if(pos != Ogre::String::npos && texname.compare(pos, texname.length() - pos, ".dds") != 0) + { + // since we know all (GOTY edition or less) textures end + // in .dds, we change the extension + texname.replace(pos, texname.length(), ".dds"); + + // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) + // verify, and revert if false (this call succeeds quickly, but fails slowly) + if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texname)) + { + texname = filename; + Misc::StringUtils::toLower(texname); + if(texname.compare(0, sizeof(path)-1, path) != 0) + texname = path + texname; + } + } + + return texname; +} + public: static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, @@ -575,47 +610,29 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int depthFlags = 3; // Default should be 1, but Bloodmoon's models are broken int specFlags = 0; - Ogre::String texName; + Ogre::String texName[7]; bool vertexColour = (shape->data->colors.size() != 0); // Texture - if(texprop && texprop->textures[0].inUse) + if(texprop) { - const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); - if(st->external) + for(int i = 0;i < 7;i++) { - /* Bethesda at some point converted all their BSA - * textures from tga to dds for increased load speed, but all - * texture file name references were kept as .tga. - */ - static const char path[] = "textures\\"; - - texName = st->filename; - Misc::StringUtils::toLower(texName); - - if(texName.compare(0, sizeof(path)-1, path) != 0) - texName = path + texName; - - Ogre::String::size_type pos = texName.rfind('.'); - if(pos != Ogre::String::npos && texName.compare(pos, texName.length() - pos, ".dds") != 0) + if(!texprop->textures[i].inUse) + continue; + if(texprop->textures[i].texture.empty()) { - // since we know all (GOTY edition or less) textures end - // in .dds, we change the extension - texName.replace(pos, texName.length(), ".dds"); - - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - { - texName = st->filename; - Misc::StringUtils::toLower(texName); - if(texName.compare(0, sizeof(path)-1, path) != 0) - texName = path + texName; - } + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name+"\n"); + continue; } + + const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); + if(st->external) + texName[i] = findTextureName(st->filename); + else + warn("Found internal texture, ignoring."); } - else warn("Found internal texture, ignoring."); } // Alpha modifiers @@ -655,8 +672,6 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String alpha = matprop->data.alpha; } - Ogre::String matname = name; - if(matprop || !texName.empty()) { // Generate a hash out of all properties that can affect the material. size_t h = 0; @@ -672,7 +687,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, emissive.x); boost::hash_combine(h, emissive.y); boost::hash_combine(h, emissive.z); - boost::hash_combine(h, texName); + for(int i = 0;i < 7;i++) + { + if(!texName[i].empty()) + boost::hash_combine(h, texName[i]); + } boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); @@ -687,11 +706,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String return itr->second; } // not found, create a new one - MaterialMap.insert(std::make_pair(h, matname)); + MaterialMap.insert(std::make_pair(h, name)); } // No existing material like this. Create a new one. - sh::MaterialInstance* instance = sh::Factory::getInstance ().createMaterialInstance (matname, "openmw_objects_base"); + sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); if(vertMode == 0 || !vertexColour) { instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); @@ -722,13 +741,18 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } - instance->setProperty("diffuseMap", sh::makeProperty(texName)); + instance->setProperty("diffuseMap", sh::makeProperty(texName[0])); + for(int i = 1;i < 7;i++) + { + if(!texName[i].empty()) + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); + } if (vertexColour) instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Add transparency if NiAlphaProperty was present - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); if (result.first) { alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ @@ -763,8 +787,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); // depth_func??? - sh::Factory::getInstance()._ensureMaterial(matname, "Default"); - return matname; + sh::Factory::getInstance()._ensureMaterial(name, "Default"); + return name; } }; From 512534be11a670c0102299bad95fa61264d3e604 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Apr 2013 22:58:07 -0700 Subject: [PATCH 090/817] Read the correct texture resource for other layers --- components/nifogre/ogrenifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index b3ab4c016..d1ce7ae31 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -627,7 +627,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String continue; } - const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); + const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); if(st->external) texName[i] = findTextureName(st->filename); else From aac2ba1d5fff2e3b4ebfe22125343ac7aa027b62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 12:24:13 +0200 Subject: [PATCH 091/817] Fix loading screen looking for wallpapers in a fixed group. --- apps/openmw/mwgui/loadingscreen.cpp | 20 +++++++++++++------- apps/openmw/mwgui/loadingscreen.hpp | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index e7c7acb53..86f196d9f 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -217,15 +217,21 @@ namespace MWGui void LoadingScreen::changeWallpaper () { - if (mResources.isNull ()) - mResources = Ogre::ResourceGroupManager::getSingleton ().findResourceNames ("General", "Splash_*.tga"); - - - if (mResources->size()) + if (mResources.empty()) { - std::string const & randomSplash = mResources->at (rand() % mResources->size()); + Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); + for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + { + Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash_*.tga"); + mResources.insert(mResources.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); + } + } - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); + if (!mResources.empty()) + { + std::string const & randomSplash = mResources.at (rand() % mResources.size()); + + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); mBackgroundImage->setImageTexture (randomSplash); } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 24b385071..176fc0f5d 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -44,7 +44,7 @@ namespace MWGui Ogre::Rectangle2D* mRectangle; Ogre::MaterialPtr mBackgroundMaterial; - Ogre::StringVectorPtr mResources; + Ogre::StringVector mResources; bool mLoadingOn; From 095daca058e980471af9391b027e0f83f28c494b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 03:26:21 -0700 Subject: [PATCH 092/817] Create entities when iterating through the NIF --- components/nifogre/ogrenifloader.cpp | 185 ++++++++++++--------------- components/nifogre/ogrenifloader.hpp | 14 -- 2 files changed, 79 insertions(+), 120 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d1ce7ae31..89f55fbd4 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1088,9 +1088,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader typedef std::map LoaderMap; static LoaderMap sLoaders; -public: - NIFMeshLoader() - { } + NIFMeshLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1113,25 +1111,25 @@ public: findTriShape(mesh, node, NULL, NULL, NULL, NULL, NULL, NULL); } - void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) + void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) { // Do not create meshes for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) return; - flags |= node->flags; - // Marker objects: just skip the entire node /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) return; + flags |= node->flags; + Nif::ExtraPtr e = node->extra; while(!e.empty()) { - Nif::NiStringExtraData *sd; - if((sd=dynamic_cast(e.getPtr())) != NULL) + if(e->recType == Nif::RC_NiStringExtraData) { + const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj if(sd->string == "MRK") @@ -1146,7 +1144,7 @@ public: if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { - const Nif::NiTriShape *shape = dynamic_cast(node); + const Nif::NiTriShape *shape = static_cast(node); Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); @@ -1165,7 +1163,15 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), shape->name)); + entities.mEntities.push_back(sceneMgr->createEntity(mesh)); + if(entities.mSkelBase) + { + Ogre::Entity *entity = entities.mEntities.back(); + if(entity->hasSkeleton()) + entity->shareSkeletonInstanceWith(entities.mSkelBase); + else + entities.mSkelBase->attachObjectToBone(shape->name, entity); + } } const Nif::NiNode *ninode = dynamic_cast(node); @@ -1175,12 +1181,12 @@ public: for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createMeshes(children[i].getPtr(), meshes, flags); + createEntities(sceneMgr, children[i].getPtr(), entities, flags); } } } - void createEmptyMesh(const Nif::Node *node, MeshInfoList &meshes) + void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all @@ -1199,91 +1205,61 @@ public: mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), node->name)); + entities.mSkelBase = sceneMgr->createEntity(mesh); + entities.mEntities.push_back(entities.mSkelBase); + } + +public: + NIFMeshLoader() : mShapeIndex(~(size_t)0) + { } + + static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) + { + Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); + Nif::NIFFile &nif = *pnif.get(); + if(nif.numRecords() < 1) + { + nif.warn("Found no NIF records in "+name+"."); + return; + } + + // The first record is assumed to be the root node + const Nif::Record *r = nif.getRecord(0); + assert(r != NULL); + + const Nif::Node *node = dynamic_cast(r); + if(node == NULL) + { + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return; + } + + bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); + if(!hasSkel) + hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); + + NIFMeshLoader meshldr(name, group); + if(hasSkel) + meshldr.createSkelBase(sceneMgr, node, entities); + meshldr.createEntities(sceneMgr, node, entities); } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -typedef std::map MeshInfoMap; -static MeshInfoMap sMeshInfoMap; - -MeshInfoList Loader::load(const std::string &name, const std::string &group) -{ - MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name); - if(meshiter != sMeshInfoMap.end()) - return meshiter->second; - - MeshInfoList &meshes = sMeshInfoMap[name]; - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) - { - nif.warn("Found no NIF records in "+name+"."); - return meshes; - } - - // The first record is assumed to be the root node - Nif::Record const *r = nif.getRecord(0); - assert(r != NULL); - - Nif::Node const *node = dynamic_cast(r); - if(node == NULL) - { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return meshes; - } - - bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); - if(!hasSkel) - hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - - NIFMeshLoader meshldr(name, group); - if(hasSkel) - meshldr.createEmptyMesh(node, meshes); - meshldr.createMeshes(node, meshes, 0); - - return meshes; -} - EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, group); - if(meshes.size() == 0) - return entitylist; + NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); - Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - for(size_t i = 0;i < meshes.size();i++) + for(size_t i = 0;i < entitylist.mEntities.size();i++) { - entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].mMeshName)); - Ogre::Entity *entity = entitylist.mEntities.back(); - if(!entitylist.mSkelBase && entity->hasSkeleton()) - entitylist.mSkelBase = entity; - } - - if(entitylist.mSkelBase) - { - parentNode->attachObject(entitylist.mSkelBase); - for(size_t i = 0;i < entitylist.mEntities.size();i++) - { - Ogre::Entity *entity = entitylist.mEntities[i]; - if(entity != entitylist.mSkelBase && entity->hasSkeleton()) - { - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - parentNode->attachObject(entity); - } - else if(entity != entitylist.mSkelBase) - entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - } - } - else - { - for(size_t i = 0;i < entitylist.mEntities.size();i++) - parentNode->attachObject(entitylist.mEntities[i]); + Ogre::Entity *entity = entitylist.mEntities[i]; + if(!entity->isAttached()) + parentNode->attachObject(entity); } return entitylist; @@ -1296,25 +1272,17 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, group); - if(meshes.size() == 0) - return entitylist; + NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); bool isskinned = false; - Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = "@shape=tri "+bonename; - Misc::StringUtils::toLower(filter); - for(size_t i = 0;i < meshes.size();i++) + for(size_t i = 0;i < entitylist.mEntities.size();i++) { - Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); - if(!entitylist.mSkelBase) + Ogre::Entity *ent = entitylist.mEntities[i]; + if(entitylist.mSkelBase != ent && ent->hasSkeleton()) { - if(ent->hasSkeleton()) - entitylist.mSkelBase = ent; - } - else if(!isskinned && ent->hasSkeleton()) isskinned = true; - entitylist.mEntities.push_back(ent); + break; + } } Ogre::Vector3 scale(1.0f); @@ -1323,20 +1291,21 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(isskinned) { + std::string filter = "@shape=tri "+bonename; + Misc::StringUtils::toLower(filter); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity->hasSkeleton()) { - if(entity != entitylist.mSkelBase) - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - if(entity->getMesh()->getName().find(filter) != std::string::npos) + if(entity == entitylist.mSkelBase || + entity->getMesh()->getName().find(filter) != std::string::npos) parentNode->attachObject(entity); } else { - if(entity->getMesh()->getName().find(filter) != std::string::npos) - entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + if(entity->getMesh()->getName().find(filter) == std::string::npos) + entity->detachFromParent(); } } } @@ -1344,8 +1313,12 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen { for(size_t i = 0;i < entitylist.mEntities.size();i++) { - Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entitylist.mEntities[i]); - tag->setScale(scale); + Ogre::Entity *entity = entitylist.mEntities[i]; + if(!entity->isAttached()) + { + Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); + tag->setScale(scale); + } } } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index b8b2e3c00..92b153468 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -48,22 +48,8 @@ struct EntityList { }; -/* This holds a list of mesh names, the names of their parent nodes, and the offset - * from their parent nodes. */ -struct MeshInfo { - std::string mMeshName; - std::string mTargetNode; - - MeshInfo(const std::string &name, const std::string &target) - : mMeshName(name), mTargetNode(target) - { } -}; -typedef std::vector MeshInfoList; - class Loader { - static MeshInfoList load(const std::string &name, const std::string &group); - public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, From f0d49fdbd06f99a297bb39c80b0b14317aade26e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 12:28:57 +0200 Subject: [PATCH 093/817] Create separate groups for each data dir / BSA file. --- apps/openmw/engine.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 948a06d47..17610e479 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -154,26 +154,36 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { + // We use separate resource groups to handle location priority. const Files::PathContainer& dataDirs = mFileCollections.getPaths(); - std::string dataDirectory; + + int i=0; for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { - dataDirectory = iter->string(); + // Last data dir has the highest priority + std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i); + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); + + std::string dataDirectory = iter->string(); std::cout << "Data dir " << dataDirectory << std::endl; - Bsa::addDir(dataDirectory, mFSStrict); + Bsa::addDir(dataDirectory, mFSStrict, groupName); + ++i; } - // BSA resources are put into a separate group. We want loose files to have priority over BSA resources, and this seems - // to be the only way to get Ogre to do just that. - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup ("GroupBSA"); - + i=0; for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) { if (mFileCollections.doesExist(*archive)) { + // Last BSA has the highest priority + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(dataDirs.size()-i); + + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); + const std::string archivePath = mFileCollections.getPath(*archive).string(); std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath, "GroupBSA"); + Bsa::addBSA(archivePath, groupName); + ++i; } else { From 5625d73d84488a2c4eb2ff51270329a972733285 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 17:16:34 +0200 Subject: [PATCH 094/817] Bump texture support --- components/nif/property.hpp | 11 ++ components/nifogre/ogrenifloader.cpp | 26 ++++- extern/shiny/Docs/Macros.dox | 23 ++++- extern/shiny/Main/MaterialInstance.hpp | 1 + extern/shiny/Main/ShaderInstance.cpp | 15 +-- extern/shiny/Main/ShaderSet.cpp | 16 +++ extern/shiny/Main/ShaderSet.hpp | 4 + files/materials/objects.mat | 7 ++ files/materials/objects.shader | 134 +++++++++++++++++++++++-- 9 files changed, 211 insertions(+), 26 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index cd1e0a5d1..00cdc0e00 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -109,6 +109,17 @@ public: * 5 - Bump map texture * 6 - Decal texture */ + enum TextureType + { + BaseTexture = 0, + DarkTexture = 1, + DetailTexture = 2, + GlossTexture = 3, + GlowTexture = 4, + BumpTexture = 5, + DecalTexture = 6 + }; + Texture textures[7]; void read(NIFStream *nif) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 89f55fbd4..c5dc7fbb9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -555,11 +555,14 @@ static std::string findTextureName(const std::string &filename) * texture file name references were kept as .tga. */ static const char path[] = "textures\\"; + static const char path2[] = "textures/"; + std::string texname = filename; Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0) + if(texname.compare(0, sizeof(path)-1, path) != 0 + && texname.compare(0, sizeof(path2)-1, path2) != 0) texname = path + texname; Ogre::String::size_type pos = texname.rfind('.'); @@ -575,7 +578,8 @@ static std::string findTextureName(const std::string &filename) { texname = filename; Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0) + if(texname.compare(0, sizeof(path)-1, path) != 0 + && texname.compare(0, sizeof(path2)-1, path2) != 0) texname = path + texname; } } @@ -590,7 +594,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String const Nif::NiAlphaProperty *alphaprop, const Nif::NiVertexColorProperty *vertprop, const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + const Nif::NiSpecularProperty *specprop, + bool &needTangents) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -634,6 +639,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String warn("Found internal texture, ignoring."); } } + needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); // Alpha modifiers if(alphaprop) @@ -741,7 +747,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } - instance->setProperty("diffuseMap", sh::makeProperty(texName[0])); + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); for(int i = 1;i < 7;i++) { if(!texName[i].empty()) @@ -1022,11 +1029,20 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } + bool needTangents=false; std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup, texprop, matprop, alphaprop, - vertprop, zprop, specprop); + vertprop, zprop, specprop, needTangents); if(matname.length() > 0) sub->setMaterialName(matname); + + // build tangents if the material needs them + if (needTangents) + { + unsigned short src,dest; + if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) + mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); + } } bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, diff --git a/extern/shiny/Docs/Macros.dox b/extern/shiny/Docs/Macros.dox index 0578c447f..c04ebd374 100644 --- a/extern/shiny/Docs/Macros.dox +++ b/extern/shiny/Docs/Macros.dox @@ -107,6 +107,23 @@ \section properties Property retrieval / binding + \subsection shPropertyHasValue shPropertyHasValue + + Usage: \@shPropertyHasValue(property) + + Gets replaced by 1 if the property's value is not empty, or 0 if it is empty. + Useful for checking whether an optional texture is present or not. + + Example: + \code + #if @shPropertyHasValue(specularMap) + // specular mapping code + #endif + #if @shPropertyHasValue(normalMap) + // normal mapping code + #endif + \endcode + \subsection shUniformProperty shUniformProperty Usage: \@shUniformProperty<4f|3f|2f|1f|int> (uniformName, property) @@ -130,15 +147,11 @@ Example: \code - #if @shPropertyBool(has_normal_map) + #if @shPropertyBool(has_vertex_colors) ... #endif \endcode - \subsection shPropertyNotBool shPropertyNotBool - - Same as shPropertyBool, but inverts the result (i.e. when shPropertyBool would return 0, this returns 1 and vice versa) - \subsection shPropertyString shPropertyString Retrieve a string property of the pass that this shader belongs to diff --git a/extern/shiny/Main/MaterialInstance.hpp b/extern/shiny/Main/MaterialInstance.hpp index 000f9d60c..36ba37ddb 100644 --- a/extern/shiny/Main/MaterialInstance.hpp +++ b/extern/shiny/Main/MaterialInstance.hpp @@ -25,6 +25,7 @@ namespace sh public: virtual void requestedConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called before creating virtual void createdConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called after creating + virtual ~MaterialInstanceListener(){} }; /** diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp index 1539128ab..b44c63c32 100644 --- a/extern/shiny/Main/ShaderInstance.cpp +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -194,13 +194,6 @@ namespace sh bool val = retrieveValue(value, properties->getContext()).get(); replaceValue = val ? "1" : "0"; } - else if (cmd == "shPropertyNotBool") // same as above, but inverts the result - { - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - bool val = retrieveValue(value, properties->getContext()).get(); - replaceValue = val ? "0" : "1"; - } else if (cmd == "shPropertyString") { std::string propertyName = args[0]; @@ -214,6 +207,14 @@ namespace sh std::string value = retrieveValue(properties->getProperty(propertyName), properties->getContext()).get(); replaceValue = (value == comparedAgainst) ? "1" : "0"; } + else if (isCmd(source, pos, "@shPropertyHasValue")) + { + assert(args.size() == 1); + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + std::string val = retrieveValue(value, properties->getContext()).get(); + replaceValue = (val.empty() ? "0" : "1"); + } else throw std::runtime_error ("unknown command \"" + cmd + "\""); source.replace(pos, (end+1)-pos, replaceValue); diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp index 413d7d1a2..628e0acee 100644 --- a/extern/shiny/Main/ShaderSet.cpp +++ b/extern/shiny/Main/ShaderSet.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Factory.hpp" @@ -26,6 +27,10 @@ namespace sh std::ifstream stream(sourceFile.c_str(), std::ifstream::in); std::stringstream buffer; + boost::filesystem::path p (sourceFile); + p = p.branch_path(); + mBasePath = p.string(); + buffer << stream.rdbuf(); stream.close(); mSource = buffer.str(); @@ -52,6 +57,12 @@ namespace sh size_t start = currentToken.find('(')+1; mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start)); } + else if (boost::starts_with(currentToken, "@shPropertyHasValue")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); + size_t start = currentToken.find('(')+1; + mPropertiesToExist.push_back(currentToken.substr(start, currentToken.find(')')-start)); + } else if (boost::starts_with(currentToken, "@shPropertyEqual")) { assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos) @@ -135,6 +146,11 @@ namespace sh { boost::hash_combine(seed, retrieveValue(currentGlobalSettings->getProperty(*it), NULL).get()); } + for (std::vector::iterator it = mPropertiesToExist.begin(); it != mPropertiesToExist.end(); ++it) + { + std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); + boost::hash_combine(seed, static_cast(v != "")); + } boost::hash_combine(seed, static_cast(Factory::getInstance().getCurrentLanguage())); return seed; } diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp index a423b6779..b21278ac9 100644 --- a/extern/shiny/Main/ShaderSet.hpp +++ b/extern/shiny/Main/ShaderSet.hpp @@ -53,6 +53,10 @@ namespace sh std::vector mGlobalSettings; ///< names of the global settings that affect the shader source std::vector mProperties; ///< names of the per-material properties that affect the shader source + std::vector mPropertiesToExist; + ///< same as mProperties, however in this case, it is only relevant if the property is empty or not + /// (we don't care about the value) + ShaderInstanceMap mInstances; ///< maps permutation ID (generated from the properties) to \a ShaderInstance void parse(); ///< find out which properties and global settings affect the shader source diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 5e18a666a..00b43a9d0 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -6,6 +6,7 @@ material openmw_objects_base emissive 0.0 0.0 0.0 vertmode 0 diffuseMap black.png + normalMap is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default @@ -22,6 +23,7 @@ material openmw_objects_base { vertexcolor_mode $vertmode is_transparent $is_transparent + normalMap $normalMap } diffuse $diffuse @@ -38,6 +40,11 @@ material openmw_objects_base direct_texture $diffuseMap create_in_ffp true } + + texture_unit normalMap + { + direct_texture $normalMap + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index c8616e9d1..73968a6b3 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -14,13 +14,15 @@ #define NEED_DEPTH #endif +#define NORMAL_MAP @shPropertyHasValue(normalMap) + +// if normal mapping is enabled, we force pixel lighting +#define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) #define UNDERWATER @shGlobalSettingBool(render_refraction) #define VERTEXCOLOR_MODE @shPropertyString(vertexcolor_mode) -#define VERTEX_LIGHTING 1 - #define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) #ifdef SH_VERTEX_SHADER @@ -42,6 +44,16 @@ shVertexInput(float2, uv0) shOutput(float2, UV) shNormalInput(float4) + +#if NORMAL_MAP + shTangentInput(float4) + shOutput(float3, tangentPassthrough) +#endif + +#if !VERTEX_LIGHTING + shOutput(float3, normalPassthrough) +#endif + #ifdef NEED_DEPTH shOutput(float, depthPassthrough) #endif @@ -52,6 +64,10 @@ shColourInput(float4) #endif +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + shOutput(float4, colourPassthrough) +#endif + #if VERTEX_LIGHTING shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) @@ -94,6 +110,15 @@ { shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; +#if NORMAL_MAP + tangentPassthrough = tangent.xyz; +#endif +#if !VERTEX_LIGHTING + normalPassthrough = normal.xyz; +#endif +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + colourPassthrough = colour; +#endif #ifdef NEED_DEPTH @@ -188,15 +213,31 @@ #endif SH_BEGIN_PROGRAM - shSampler2D(diffuseMap) - shInput(float2, UV) + shSampler2D(diffuseMap) + +#if NORMAL_MAP + shSampler2D(normalMap) +#endif + + shInput(float2, UV) + +#if NORMAL_MAP + shInput(float3, tangentPassthrough) +#endif +#if !VERTEX_LIGHTING + shInput(float3, normalPassthrough) +#endif #ifdef NEED_DEPTH shInput(float, depthPassthrough) #endif shInput(float3, objSpacePositionPassthrough) - + +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + shInput(float4, colourPassthrough) +#endif + #if FOG shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) @@ -222,23 +263,98 @@ #if (UNDERWATER) || (FOG) shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) - shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) + shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) #endif #if UNDERWATER - shUniform(float, waterLevel) @shSharedParameter(waterLevel) + shUniform(float, waterLevel) @shSharedParameter(waterLevel) shUniform(float, waterEnabled) @shSharedParameter(waterEnabled) #endif #if VERTEX_LIGHTING shInput(float4, lightResult) shInput(float3, directionalResult) +#else + shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) + shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) + shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) + #if VERTEXCOLOR_MODE != 2 + shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) + #endif + #if VERTEXCOLOR_MODE != 2 + shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) + #endif + #if VERTEXCOLOR_MODE != 1 + shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + #endif #endif SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV); - + +#if NORMAL_MAP + float3 normal = normalPassthrough; + float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); + float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); + + #if SH_GLSL + tbn = transpose(tbn); + #endif + + float3 TSnormal = shSample(normalMap, UV.xy).xyz * 2 - 1; + + normal = normalize (shMatrixMult( transpose(tbn), TSnormal )); +#endif + +#if !VERTEX_LIGHTING + float3 viewPos = shMatrixMult(worldView, float4(objSpacePositionPassthrough,1)).xyz; + float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); + + float3 lightDir; + float d; + float4 lightResult = float4(0,0,0,1); + @shForeach(@shGlobalSettingString(num_lights)) + lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); + d = length(lightDir); + lightDir = normalize(lightDir); + +#if VERTEXCOLOR_MODE == 2 + lightResult.xyz += colourPassthrough.xyz * lightDiffuse[@shIterator].xyz + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * max(dot(viewNormal.xyz, lightDir), 0); +#else + lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * max(dot(viewNormal.xyz, lightDir), 0); +#endif + +#if @shIterator == 0 + float3 directionalResult = lightResult.xyz; +#endif + + @shEndForeach + + +#if VERTEXCOLOR_MODE == 2 + lightResult.xyz += lightAmbient.xyz * colourPassthrough.xyz + materialEmissive.xyz; + lightResult.a *= colourPassthrough.a; +#endif +#if VERTEXCOLOR_MODE == 1 + lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + colourPassthrough.xyz; +#endif +#if VERTEXCOLOR_MODE == 0 + lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; +#endif + +#if VERTEXCOLOR_MODE != 2 + lightResult.a *= materialDiffuse.a; +#endif +#endif + // shadows only for the first (directional) light #if SHADOWS float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); @@ -275,7 +391,7 @@ #if FOG float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - + #if UNDERWATER shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); From ae3e4ecf8b7598a021970ab2c3f1a75650822781 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:02:30 +0200 Subject: [PATCH 095/817] Finished enchanting --- apps/openmw/mwgui/enchantingdialog.cpp | 20 ++++++++++++++++++-- apps/openmw/mwgui/enchantingdialog.hpp | 1 + apps/openmw/mwmechanics/enchanting.cpp | 3 ++- files/mygui/openmw_enchanting_dialog.layout | 4 ++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 1ed80127d..23e400c36 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -32,6 +32,7 @@ namespace MWGui getWidget(mTypeButton, "TypeButton"); getWidget(mBuyButton, "BuyButton"); getWidget(mPrice, "PriceLabel"); + getWidget(mPriceText, "PriceTextLabel"); setWidgets(mAvailableEffectsList, mUsedEffectsView); @@ -94,19 +95,34 @@ namespace MWGui mPtr = actor; startEditing (); + + mPrice->setVisible(true); } void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::Ptr gem = soulgem; mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); mPtr = player; startEditing(); - mEnchanting.setSoulGem(gem); + mEnchanting.setSoulGem(soulgem); + + MyGUI::ImageBox* image = mSoulBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(soulgem).getInventoryIcon(soulgem); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture (path); + image->setUserString ("ToolTipType", "ItemPtr"); + image->setUserData(soulgem); + image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); + + mPrice->setVisible(false); + mPriceText->setVisible(false); } void EnchantingDialog::onReferenceUnavailable () diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 347b37e90..a7861c422 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -56,6 +56,7 @@ namespace MWGui MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; MyGUI::TextBox* mPrice; + MyGUI::TextBox* mPriceText; MWMechanics::Enchanting mEnchanting; ESM::EffectList mEffectList; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 45db667d2..884c4d896 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -88,7 +88,8 @@ namespace MWMechanics MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); - payForEnchantment(); + if(!mSelfEnchanting) + payForEnchantment(); return true; } diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 41b8ffa93..f64d21dea 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -97,11 +97,11 @@ - + - + From 21796197217e50a3cffe24f95008a46edd42da62 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:06:11 +0200 Subject: [PATCH 096/817] Small enchanting fix --- apps/openmw/mwgui/enchantingdialog.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 23e400c36..276e7a904 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -95,8 +95,6 @@ namespace MWGui mPtr = actor; startEditing (); - - mPrice->setVisible(true); } void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) @@ -123,6 +121,7 @@ namespace MWGui mPrice->setVisible(false); mPriceText->setVisible(false); + updateLabels(); } void EnchantingDialog::onReferenceUnavailable () From 30654a1faa0d9181e4beb28babfd09fd801b809b Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:11:57 +0200 Subject: [PATCH 097/817] Added removing of ogre static. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d31e4afc8..f517a4da8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq + - sudo apt-get remove -qq libogre-static-dev - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: From 4bf87948a03e6073c2c527c25f7ee45d7ba47c18 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:19:46 +0200 Subject: [PATCH 098/817] Removed clang compilation target. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f517a4da8..4852efb81 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: cpp compiler: - - clang - gcc before_script: - mkdir build From 08e9bb0236447d7a952f13791180ba122a5fad4a Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:25:40 +0200 Subject: [PATCH 099/817] Another small enchanting fix --- apps/openmw/mwmechanics/enchanting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 884c4d896..d92acdafc 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -7,6 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include namespace MWMechanics { @@ -56,7 +57,7 @@ namespace MWMechanics enchantment.mData.mCharge = getGemCharge(); //Exception for Azura Star, it's not destroyed after enchanting - if(mSoulGemPtr.get()->mBase->mId=="Misc_SoulGem_Azura") + if(boost::iequals(mSoulGemPtr.get()->mBase->mId, "Misc_SoulGem_Azura")) mSoulGemPtr.getCellRef().mSoul=""; else mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); From 71b4319a0ce170b9815c480ee5e5a1cb2b1f0d6f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:31:38 +0200 Subject: [PATCH 100/817] Yet another change in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4852efb81..a9c47aa4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev libboost-program-options-dev libboost-system-dev libboost-wave-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-dev libqt4-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From a9b56eedc3c220a108915d3caf9234a60129c99e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 18:51:40 +0200 Subject: [PATCH 101/817] Support NIF "glow maps", which are basically an emissive channel. --- components/nif/property.hpp | 4 ++-- components/nifogre/ogrenifloader.cpp | 7 ++++++ files/materials/objects.mat | 14 ++++++++++++ files/materials/objects.shader | 33 ++++++++++++++++++++++++---- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 00cdc0e00..fd96ad048 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -64,7 +64,7 @@ public: bool inUse; NiSourceTexturePtr texture; - int clamp, set, filter; + int clamp, uvSet, filter; short unknown2; void read(NIFStream *nif) @@ -75,7 +75,7 @@ public: texture.read(nif); clamp = nif->getInt(); filter = nif->getInt(); - set = nif->getInt(); + uvSet = nif->getInt(); // I have no idea, but I think these are actually two // PS2-specific shorts (ps2L and ps2K), followed by an unknown diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index c5dc7fbb9..f8eca821f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -749,6 +749,13 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); + if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) + { + instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); + } + for(int i = 1;i < 7;i++) { if(!texName[i].empty()) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 00b43a9d0..8740c82c3 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -7,6 +7,9 @@ material openmw_objects_base vertmode 0 diffuseMap black.png normalMap + emissiveMap + use_emissive_map false + emissiveMapUVSet 0 is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default @@ -24,6 +27,8 @@ material openmw_objects_base vertexcolor_mode $vertmode is_transparent $is_transparent normalMap $normalMap + emissiveMapUVSet $emissiveMapUVSet + emissiveMap $emissiveMap } diffuse $diffuse @@ -39,12 +44,21 @@ material openmw_objects_base { direct_texture $diffuseMap create_in_ffp true + tex_coord_set $emissiveMapUVSet } texture_unit normalMap { direct_texture $normalMap } + + texture_unit emissiveMap + { + create_in_ffp $use_emissive_map + colour_op add + direct_texture $emissiveMap + tex_coord_set $emissiveMapUVSet + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 73968a6b3..d0e817373 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -15,6 +15,10 @@ #endif #define NORMAL_MAP @shPropertyHasValue(normalMap) +#define EMISSIVE_MAP @shPropertyHasValue(emissiveMap) + +// right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more +#define SECOND_UV_SET @shPropertyString(emissiveMapUVSet) // if normal mapping is enabled, we force pixel lighting #define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) @@ -42,7 +46,11 @@ #endif shVertexInput(float2, uv0) - shOutput(float2, UV) +#if SECOND_UV_SET + shVertexInput(float2, uv1) +#endif + shOutput(float4, UV) + shNormalInput(float4) #if NORMAL_MAP @@ -109,7 +117,12 @@ SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV = uv0; + + UV.xy = uv0; +#if SECOND_UV_SET + UV.zw = uv1; +#endif + #if NORMAL_MAP tangentPassthrough = tangent.xyz; #endif @@ -219,7 +232,11 @@ shSampler2D(normalMap) #endif - shInput(float2, UV) +#if EMISSIVE_MAP + shSampler2D(emissiveMap) +#endif + + shInput(float4, UV) #if NORMAL_MAP shInput(float3, tangentPassthrough) @@ -294,7 +311,7 @@ SH_START_PROGRAM { - shOutputColour(0) = shSample(diffuseMap, UV); + shOutputColour(0) = shSample(diffuseMap, UV.xy); #if NORMAL_MAP float3 normal = normalPassthrough; @@ -399,6 +416,14 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); #endif +#endif + +#if EMISSIVE_MAP + #if SECOND_UV_SET + shOutputColour(0).xyz += shSample(emissiveMap, UV.zw).xyz; + #else + shOutputColour(0).xyz += shSample(emissiveMap, UV.xy).xyz; + #endif #endif // prevent negative colour output (for example with negative lights) From 2a5fc7cd822e9a204b63bfdf858cec1c7eefba53 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:02:21 +0200 Subject: [PATCH 102/817] Change in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a9c47aa4e..4d1257d2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev libboost-program-options-dev libboost-system-dev libboost-wave-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-dev libqt4-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev -script: make + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev 0ibpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev +script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: - master From f655b9997cc4e04f606f726452ad241eabe57c5c Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:10:57 +0200 Subject: [PATCH 103/817] Added printing CMakeCache.txt file For debug purposes, should be removed if compilation succeed. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4d1257d2b..d99809590 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ before_script: - mkdir build - cd build - cmake .. -DMYGUI_STATIC=1 + - cat CMakeCache.txt before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps From d070860f0943c2fa5ac22762128554b5fcf623be Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:14:13 +0200 Subject: [PATCH 104/817] Fixed typo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d99809590..7f361f5d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev 0ibpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: From af509ce016ee85094fcd75f69eadf29109c2757f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:19:25 +0200 Subject: [PATCH 105/817] Restored building with static ogre. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7f361f5d4..db0a47d84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DMYGUI_STATIC=1 + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 - cat CMakeCache.txt before_install: - git submodule update --init --recursive From 8ca88d1a708b05741240eb1e1b04d63449f2f2ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 21:13:01 +0200 Subject: [PATCH 106/817] Fix merchant repair menu allowing repair of repair items --- apps/openmw/mwgui/merchantrepair.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 0a6532605..1c9056748 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -40,7 +40,8 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); - for (MWWorld::ContainerStoreIterator iter (store.begin()); + int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; + for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); iter!=store.end(); ++iter) { if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) From 43cdbd033d690dd904bf6f98dd39423f3182443f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 21:14:49 +0200 Subject: [PATCH 107/817] Display remaining item health / enchantment charge in HUD icons, display remaining enchanment charge in tooltips --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwclass/armor.cpp | 2 ++ apps/openmw/mwclass/clothing.cpp | 2 ++ apps/openmw/mwclass/weapon.cpp | 3 +++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 4 ++-- apps/openmw/mwgui/tooltips.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 9 +++++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++-- 11 files changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b271aed18..976d7d84c 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -182,8 +182,8 @@ namespace MWBase virtual void activateQuickKey (int index) = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; - virtual void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) = 0; - virtual void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) = 0; + virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0; + virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0; virtual void unsetSelectedSpell() = 0; virtual void unsetSelectedWeapon() = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index b94c270d5..320944d3c 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -260,6 +260,8 @@ namespace MWClass } info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; info.text = text; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index d65376898..abad26767 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -207,6 +207,8 @@ namespace MWClass } info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; info.text = text; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index ed2a095e3..0a527262f 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -349,6 +349,9 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index aeab5f94a..001f42bd1 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -294,7 +294,7 @@ namespace MWGui if (weaponSlot == invStore.end()) mWindowManager.unsetSelectedWeapon(); else - mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability + mWindowManager.setSelectedWeapon(*weaponSlot); /// \todo track weapon durability mPreviewDirty = true; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 5ea13fb0d..2e4bf9100 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -346,7 +346,7 @@ namespace MWGui store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item, 100); /// \todo track charge % + mWindowManager.setSelectedEnchantItem(item); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d7fb0e1bc..021a849a0 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -382,7 +382,7 @@ namespace MWGui store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item, 100); /// \todo track charge % + mWindowManager.setSelectedEnchantItem(item); updateSpells(); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index af3e146bb..9292e60e5 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -456,8 +456,8 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) if (enchant->mData.mType == ESM::Enchantment::WhenStrikes || enchant->mData.mType == ESM::Enchantment::WhenUsed) { - /// \todo store the current enchantment charge somewhere - int charge = enchant->mData.mCharge; + int maxCharge = enchant->mData.mCharge; + int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; const int chargeWidth = 204; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index ba94915cc..da5a35221 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -17,6 +17,7 @@ namespace MWGui : isPotion(false) , imageSize(32) , wordWrap(true) + , remainingEnchantCharge(-1) {} std::string caption; @@ -26,6 +27,7 @@ namespace MWGui // enchantment (for cloth, armor, weapons) std::string enchant; + int remainingEnchantCharge; // effects (for potions, ingredients) Widgets::SpellEffectList effects; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c975b2cdb..f994683a6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -933,14 +933,19 @@ void WindowManager::setSelectedSpell(const std::string& spellId, int successChan mSpellWindow->setTitle(spell->mName); } -void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) +void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() + .find(MWWorld::Class::get(item).getEnchantment(item)); + + int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); } -void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) +void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { + int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c14c6b2fe..3c9fc586a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -179,8 +179,8 @@ namespace MWGui virtual void activateQuickKey (int index); virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); - virtual void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); - virtual void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); + virtual void setSelectedEnchantItem(const MWWorld::Ptr& item); + virtual void setSelectedWeapon(const MWWorld::Ptr& item); virtual void unsetSelectedSpell(); virtual void unsetSelectedWeapon(); From ebaf80d53921e51aa9b3c8cd823ef191b2490d9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 23:55:57 +0200 Subject: [PATCH 108/817] Trace actors onto the ground after load, when moved to a different cell by the console or on player cell change. --- apps/openmw/mwbase/world.hpp | 3 ++ apps/openmw/mwclass/creature.cpp | 6 +++ apps/openmw/mwclass/creature.hpp | 2 + apps/openmw/mwclass/npc.cpp | 5 ++ apps/openmw/mwclass/npc.hpp | 2 + apps/openmw/mwrender/renderingmanager.cpp | 27 +++++----- apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwrender/terrain.cpp | 11 ++++ apps/openmw/mwrender/terrain.hpp | 3 ++ .../mwscript/transformationextensions.cpp | 3 ++ apps/openmw/mwworld/class.cpp | 4 ++ apps/openmw/mwworld/class.hpp | 3 ++ apps/openmw/mwworld/physicssystem.cpp | 50 ++++++++++++++++++- apps/openmw/mwworld/physicssystem.hpp | 1 + apps/openmw/mwworld/scene.cpp | 6 ++- apps/openmw/mwworld/worldimp.cpp | 19 +++++++ apps/openmw/mwworld/worldimp.hpp | 3 ++ libs/openengine/bullet/physic.cpp | 3 +- 18 files changed, 138 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 8eea383eb..040dc703c 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -216,6 +216,9 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0; + ///< Adjust position after load to be on ground. Must be called after model load. + virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1097f8f29..04889360f 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -9,6 +9,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" @@ -86,6 +87,11 @@ namespace MWClass return ref->mBase->mId; } + void Creature::adjustPosition(const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr); + } + void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { MWRender::Actors& actors = renderingInterface.getActors(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index ea356165e..297c2ea61 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -22,6 +22,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index cd6b0def1..7cda87bb1 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -160,6 +160,11 @@ namespace MWClass return ref->mBase->mId; } + void Npc::adjustPosition(const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr); + } + void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 1a10bce6c..d1a9158fd 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -44,6 +44,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7c442c686..2f49a4031 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -529,25 +529,28 @@ void RenderingManager::applyFog (bool underwater) void RenderingManager::setAmbientMode() { - switch (mAmbientMode) - { + switch (mAmbientMode) + { case 0: - - setAmbientColour(mAmbientColor); - break; + setAmbientColour(mAmbientColor); + break; case 1: - - setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); - break; + setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); + break; case 2: - - setAmbientColour(ColourValue(1,1,1)); - break; - } + setAmbientColour(ColourValue(1,1,1)); + break; + } } +float RenderingManager::getTerrainHeightAt(Ogre::Vector3 worldPos) +{ + return mTerrainManager->getTerrainHeightAt(worldPos); +} + + void RenderingManager::configureAmbient(MWWorld::Ptr::CellStore &mCell) { mAmbientColor.setAsABGR (mCell.mCell->mAmbi.mAmbient); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index fd43438ca..b343a60bd 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -158,6 +158,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); + float getTerrainHeightAt (Ogre::Vector3 worldPos); + void setGlare(bool glare); void skyEnable (); void skyDisable (); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 438366873..c27dce6ca 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -71,6 +71,17 @@ namespace MWRender //---------------------------------------------------------------------------------------------- + float TerrainManager::getTerrainHeightAt(Vector3 worldPos) + { + Ogre::Terrain* terrain = NULL; + float height = mTerrainGroup.getHeightAtWorldPosition(worldPos, &terrain); + if (terrain == NULL) + return std::numeric_limits().min(); + return height; + } + + //---------------------------------------------------------------------------------------------- + TerrainManager::~TerrainManager() { OGRE_DELETE mTerrainGlobals; diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index 484a0dbe3..45c56390e 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -40,6 +40,9 @@ namespace MWRender{ void cellAdded(MWWorld::CellStore* store); void cellRemoved(MWWorld::CellStore* store); + + float getTerrainHeightAt (Ogre::Vector3 worldPos); + private: Ogre::TerrainGlobalOptions* mTerrainGlobals; Ogre::TerrainGroup mTerrainGroup; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index d86a6e348..000cc545d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -303,6 +303,8 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + + MWBase::Environment::get().getWorld()->adjustPosition(ptr); } else { @@ -341,6 +343,7 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + MWBase::Environment::get().getWorld()->adjustPosition(ptr); } }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 98579797c..2dfa241b3 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,6 +259,10 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } + void Class::adjustPosition(const MWWorld::Ptr& ptr) const + { + } + MWWorld::Ptr Class::copyToCellImpl(const Ptr &ptr, CellStore &cell) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e34ebdde7..de4741e38 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -81,6 +81,9 @@ namespace MWWorld ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + ///< Adjust position to stand on ground. Must be called post model load + virtual MWMechanics::CreatureStats& getCreatureStats (const Ptr& ptr) const; ///< Return creature stats or throw an exception, if class does not have creature stats /// (default implementation: throw an exceoption) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 28f331706..19ee2e517 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -88,6 +88,50 @@ namespace MWWorld } public: + static Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, OEngine::Physic::PhysicEngine *engine) + { + const ESM::Position &refpos = ptr.getRefData().getPosition(); + Ogre::Vector3 position(refpos.pos); + + bool hit=false; + bool isInterior = !ptr.getCell()->isExterior(); + + OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); + if (!physicActor) + return position; + + bool wasCollisionMode = physicActor->getCollisionMode(); + + physicActor->enableCollisions(false); + + Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); + + Ogre::Vector3 newPosition = position; + + traceResults trace; //no initialization needed + + int maxHeight = 400.f; + int steps = 100; + for (int i=0; isetOnGround(hit); + physicActor->enableCollisions(wasCollisionMode); + + if (hit) + return newPosition; + else + return position; + } + + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { @@ -318,7 +362,7 @@ namespace MWWorld btVector3 btTo = btVector3(to.x, to.y, to.z); std::pair test = mEngine->rayTest(btFrom, btTo); - if (test.first == "") { + if (test.second == -1) { return std::make_pair(false, Ogre::Vector3()); } return std::make_pair(true, ray.getPoint(len * test.second)); @@ -351,6 +395,10 @@ namespace MWWorld return MovementSolver::move(ptr, movement, time, gravity, mEngine); } + Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr) + { + return MovementSolver::traceDown(ptr, mEngine); + } void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 2e48be407..4eec9367c 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -51,6 +51,7 @@ namespace MWWorld bool toggleCollisionMode(); Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); + Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 339026ca6..c8853f484 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -51,6 +51,7 @@ namespace class_.insertObject(ptr, physics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); + class_.adjustPosition(ptr); } catch (const std::exception& e) { @@ -99,7 +100,6 @@ namespace MWWorld } mRendering.removeCell(*iter); - //mPhysics->removeObject("Unnamed_43"); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); MWBase::Environment::get().getMechanicsManager()->drop (*iter); @@ -165,6 +165,8 @@ namespace MWWorld float y = Ogre::Radian(pos.rot[1]).valueDegrees(); float z = Ogre::Radian(pos.rot[2]).valueDegrees(); world->rotateObject(player, x, y, z); + + world->adjustPosition(player); } MWBase::MechanicsManager *mechMgr = @@ -355,6 +357,8 @@ namespace MWWorld float y = Ogre::Radian(position.rot[1]).valueDegrees(); float z = Ogre::Radian(position.rot[2]).valueDegrees(); world->rotateObject(world->getPlayer().getPlayer(), x, y, z); + + world->adjustPosition(world->getPlayer().getPlayer()); return; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ae0e02c8c..2ce753b81 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -709,6 +709,7 @@ namespace MWWorld pos.pos[0] = x; pos.pos[1] = y; pos.pos[2] = z; + Ogre::Vector3 vec(x, y, z); CellStore *currCell = ptr.getCell(); @@ -822,6 +823,24 @@ namespace MWWorld } } + void World::adjustPosition(const Ptr &ptr) + { + Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); + + if (!isFlying(ptr)) + { + Ogre::Vector3 traced = mPhysics->traceDown(ptr); + if (traced.z < pos.z) + pos.z = traced.z; + } + + float terrainHeight = mRendering->getTerrainHeightAt(pos); + if (pos.z < terrainHeight) + pos.z = terrainHeight; + + moveObject(ptr, pos.x, pos.y, pos.z); + } + void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) { rotateObjectImp(ptr, Ogre::Vector3(Ogre::Degree(x).valueRadians(), diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8cff50bd1..5ae87a1ff 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -188,6 +188,9 @@ namespace MWWorld virtual Ptr searchPtrViaHandle (const std::string& handle); ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found + virtual void adjustPosition (const Ptr& ptr); + ///< Adjust position after load to be on ground. Must be called after model load. + virtual void enable (const Ptr& ptr); virtual void disable (const Ptr& ptr); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7b831d32c..f71fa4320 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -323,7 +323,8 @@ namespace Physic mHeightFieldMap [name] = hf; - dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); + dynamicsWorld->addRigidBody(body,CollisionType_World|CollisionType_Raycasting, + CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal|CollisionType_Raycasting); } void PhysicEngine::removeHeightField(int x, int y) From fea44c05d4a337ffe4f5543c94c2a9ec3ab724bc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:10:26 +0200 Subject: [PATCH 109/817] added class record verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/classcheck.cpp | 63 ++++++++++++++++++++++++++ apps/opencs/model/tools/classcheck.hpp | 29 ++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ apps/opencs/model/world/data.cpp | 10 ++++ apps/opencs/model/world/data.hpp | 4 ++ 6 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/classcheck.cpp create mode 100644 apps/opencs/model/tools/classcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index a305d90d9..adfc5f4ae 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck + stage verifier mandatoryid skillcheck classcheck ) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp new file mode 100644 index 000000000..302af6b9d --- /dev/null +++ b/apps/opencs/model/tools/classcheck.cpp @@ -0,0 +1,63 @@ + +#include "classcheck.hpp" + +#include +#include + +#include +#include + +#include "../world/universalid.hpp" + +CSMTools::ClassCheckStage::ClassCheckStage (const CSMWorld::IdCollection& classes) +: mClasses (classes) +{} + +int CSMTools::ClassCheckStage::setup() +{ + return mClasses.getSize(); +} + +void CSMTools::ClassCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Class& class_= mClasses.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId); + + // test for empty name and description + if (class_.mName.empty()) + messages.push_back (id.toString() + "|" + class_.mId + " has an empty name"); + + if (class_.mDescription.empty()) + messages.push_back (id.toString() + "|" + class_.mId + " has an empty description"); + + // test for invalid attributes + for (int i=0; i<2; ++i) + if (class_.mData.mAttribute[i]==-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Attribute #" << i << " of " << class_.mId << " is not set"; + + messages.push_back (stream.str()); + } + + // test for non-unique skill + std::map skills; // ID, number of occurrences + + for (int i=0; i<5; ++i) + for (int i2=0; i2<2; ++i2) + ++skills[class_.mData.mSkills[i][i2]]; + + for (std::map::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) + if (iter->second>1) + { + std::ostringstream stream; + + stream + << id.toString() << "|" + << ESM::Skill::indexToId (iter->first) << " is listed more than once"; + + messages.push_back (stream.str()); + } +} \ No newline at end of file diff --git a/apps/opencs/model/tools/classcheck.hpp b/apps/opencs/model/tools/classcheck.hpp new file mode 100644 index 000000000..a29d7c8b7 --- /dev/null +++ b/apps/opencs/model/tools/classcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_CLASSCHECK_H +#define CSM_TOOLS_CLASSCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that class records are internally consistent + class ClassCheckStage : public Stage + { + const CSMWorld::IdCollection& mClasses; + + public: + + ClassCheckStage (const CSMWorld::IdCollection& classes); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 33cc3cc61..84a6910ec 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -13,6 +13,7 @@ #include "reportmodel.hpp" #include "mandatoryid.hpp" #include "skillcheck.hpp" +#include "classcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -54,6 +55,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); + + mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); } return mVerifier; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 13fff7f09..fc6cc0122 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -107,6 +107,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSkills() return mSkills; } +const CSMWorld::IdCollection& CSMWorld::Data::getClasses() const +{ + return mClasses; +} + +CSMWorld::IdCollection& CSMWorld::Data::getClasses() +{ + return mClasses; +} + const CSMWorld::IdCollection& CSMWorld::Data::getFactions() const { return mFactions; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 1e2894774..16a9685a5 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -54,6 +54,10 @@ namespace CSMWorld IdCollection& getSkills(); + const IdCollection& getClasses() const; + + IdCollection& getClasses(); + const IdCollection& getFactions() const; IdCollection& getFactions(); From 06533b8d71a10139816996a3f68042b7f4aff14e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:31:10 +0200 Subject: [PATCH 110/817] additional check for using the same attribute twice in a class --- apps/opencs/model/tools/classcheck.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 302af6b9d..da2e9f19a 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -42,6 +42,15 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector& me messages.push_back (stream.str()); } + if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Class lists same attribute twice"; + + messages.push_back (stream.str()); + } + // test for non-unique skill std::map skills; // ID, number of occurrences From b5eaa464ad8cb840437a9280f278f25813e18930 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:39:43 +0200 Subject: [PATCH 111/817] added faction record verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/factioncheck.cpp | 61 ++++++++++++++++++++++++ apps/opencs/model/tools/factioncheck.hpp | 29 +++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/factioncheck.cpp create mode 100644 apps/opencs/model/tools/factioncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index adfc5f4ae..07766507f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck + stage verifier mandatoryid skillcheck classcheck factioncheck ) diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp new file mode 100644 index 000000000..ea4a87eec --- /dev/null +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -0,0 +1,61 @@ + +#include "factioncheck.hpp" + +#include +#include + +#include +#include + +#include "../world/universalid.hpp" + +CSMTools::FactionCheckStage::FactionCheckStage (const CSMWorld::IdCollection& factions) +: mFactions (factions) +{} + +int CSMTools::FactionCheckStage::setup() +{ + return mFactions.getSize(); +} + +void CSMTools::FactionCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Faction& faction = mFactions.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Faction, faction.mId); + + // test for empty name + if (faction.mName.empty()) + messages.push_back (id.toString() + "|" + faction.mId + " has an empty name"); + + // test for invalid attributes + if (faction.mData.mAttributes[0]==faction.mData.mAttributes[1] && faction.mData.mAttributes[0]!=-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Faction lists same attribute twice"; + + messages.push_back (stream.str()); + } + + // test for non-unique skill + std::map skills; // ID, number of occurrences + + for (int i=0; i<6; ++i) + if (faction.mData.mSkills[i]!=-1) + ++skills[faction.mData.mSkills[i]]; + + for (std::map::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) + if (iter->second>1) + { + std::ostringstream stream; + + stream + << id.toString() << "|" + << ESM::Skill::indexToId (iter->first) << " is listed more than once"; + + messages.push_back (stream.str()); + } + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/factioncheck.hpp b/apps/opencs/model/tools/factioncheck.hpp new file mode 100644 index 000000000..868650572 --- /dev/null +++ b/apps/opencs/model/tools/factioncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_FACTIONCHECK_H +#define CSM_TOOLS_FACTIONCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that faction records are internally consistent + class FactionCheckStage : public Stage + { + const CSMWorld::IdCollection& mFactions; + + public: + + FactionCheckStage (const CSMWorld::IdCollection& factions); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 84a6910ec..db45de43e 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -14,6 +14,7 @@ #include "mandatoryid.hpp" #include "skillcheck.hpp" #include "classcheck.hpp" +#include "factioncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -57,6 +58,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); + + mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); } return mVerifier; From 7136ac0079ed293752202416e6a1f1c9478f0a90 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:58:53 +0200 Subject: [PATCH 112/817] added missing attribute columns to faction table --- apps/esmtool/record.cpp | 8 ++++---- apps/opencs/model/tools/factioncheck.cpp | 2 +- apps/opencs/model/world/data.cpp | 2 ++ apps/openmw/mwdialogue/filter.cpp | 4 ++-- apps/openmw/mwgui/stats_window.cpp | 4 ++-- components/esm/loadfact.cpp | 2 +- components/esm/loadfact.hpp | 2 +- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 8f77e4b44..d15e7f2b0 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -679,10 +679,10 @@ void Record::print() std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl; if (mData.mData.mUnknown != -1) std::cout << " Unknown: " << mData.mData.mUnknown << std::endl; - std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttributes[0]) - << " (" << mData.mData.mAttributes[0] << ")" << std::endl; - std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttributes[1]) - << " (" << mData.mData.mAttributes[1] << ")" << std::endl; + std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute[0]) + << " (" << mData.mData.mAttribute[0] << ")" << std::endl; + std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1]) + << " (" << mData.mData.mAttribute[1] << ")" << std::endl; for (int i = 0; i != 6; i++) if (mData.mData.mSkills[i] != -1) std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index ea4a87eec..af26904ef 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -29,7 +29,7 @@ void CSMTools::FactionCheckStage::perform (int stage, std::vector& messages.push_back (id.toString() + "|" + faction.mId + " has an empty name"); // test for invalid attributes - if (faction.mData.mAttributes[0]==faction.mData.mAttributes[1] && faction.mData.mAttributes[0]!=-1) + if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) { std::ostringstream stream; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fc6cc0122..d62fd7267 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -60,6 +60,8 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + mFactions.addColumn (new AttributesColumn (0)); + mFactions.addColumn (new AttributesColumn (1)); mFactions.addColumn (new HiddenColumn); for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index ddb15d423..78969ffd0 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -569,8 +569,8 @@ bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& ac MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor); - return stats.getAttribute (faction.mData.mAttributes[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && - stats.getAttribute (faction.mData.mAttributes[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; + return stats.getAttribute (faction.mData.mAttribute[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && + stats.getAttribute (faction.mData.mAttribute[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; } bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 86019fa28..0678e9891 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -500,8 +500,8 @@ void StatsWindow::updateSkillArea() text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttributes[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttributes[1]); + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); assert(attr1 && attr2); text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 12a76f1ad..e2712d462 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -71,7 +71,7 @@ void Faction::save(ESMWriter &esm) void Faction::blank() { mName.clear(); - mData.mAttributes[0] = mData.mAttributes[1] = 0; + mData.mAttribute[0] = mData.mAttribute[1] = 0; mData.mUnknown = -1; mData.mIsHidden = 0; diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index edc4640bb..891b99647 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -34,7 +34,7 @@ struct Faction struct FADTstruct { // Which attributes we like - int mAttributes[2]; + int mAttribute[2]; RankData mRankData[10]; From e8c32d0c3db7a77ed27db957e5b1d718bb2fd961 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 11:23:17 +0200 Subject: [PATCH 113/817] MWWorld::Player cleanup --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwscript/controlextensions.cpp | 1 + apps/openmw/mwworld/cellstore.hpp | 35 +---------------- apps/openmw/mwworld/livecellref.hpp | 45 ++++++++++++++++++++++ apps/openmw/mwworld/player.cpp | 31 +++++++++++++-- apps/openmw/mwworld/player.hpp | 33 ++++++---------- 6 files changed, 88 insertions(+), 59 deletions(-) create mode 100644 apps/openmw/mwworld/livecellref.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index beb0b9aad..8a0030be4 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem + esmstore store recordcmp fallback actionrepair actionsoulgem livecellref ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 8d65dfdd5..ac53b8ee2 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -12,6 +12,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/ptr.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2e6b45bb7..0cc111cde 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -6,45 +6,12 @@ #include #include -#include "refdata.hpp" +#include "livecellref.hpp" #include "esmstore.hpp" struct C; namespace MWWorld { - class Ptr; - class ESMStore; - - /// A reference to one object (of any type) in a cell. - /// - /// Constructing this with a CellRef instance in the constructor means that - /// in practice (where D is RefData) the possibly mutable data is copied - /// across to mData. If later adding data (such as position) to CellRef - /// this would have to be manually copied across. - template - struct LiveCellRef - { - LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) - : mBase(b), mRef(cref), mData(mRef) - {} - - LiveCellRef(const X* b = NULL) - : mBase(b), mData(mRef) - {} - - // The object that this instance is based on. - const X* mBase; - - /* Information about this instance, such as 3D location and - rotation and individual type-dependent data. - */ - ESM::CellRef mRef; - - /// runtime-data - RefData mData; - }; - - template bool operator==(const LiveCellRef& ref, int pRefnum); /// A list of cell references template diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp new file mode 100644 index 000000000..4c5efb861 --- /dev/null +++ b/apps/openmw/mwworld/livecellref.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_MWWORLD_LIVECELLREF_H +#define GAME_MWWORLD_LIVECELLREF_H + +#include + +#include "refdata.hpp" + +namespace MWWorld +{ + class Ptr; + class ESMStore; + + /// A reference to one object (of any type) in a cell. + /// + /// Constructing this with a CellRef instance in the constructor means that + /// in practice (where D is RefData) the possibly mutable data is copied + /// across to mData. If later adding data (such as position) to CellRef + /// this would have to be manually copied across. + template + struct LiveCellRef + { + LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) + : mBase(b), mRef(cref), mData(mRef) + {} + + LiveCellRef(const X* b = NULL) + : mBase(b), mData(mRef) + {} + + // The object that this instance is based on. + const X* mBase; + + /* Information about this instance, such as 3D location and + rotation and individual type-dependent data. + */ + ESM::CellRef mRef; + + /// runtime-data + RefData mData; + }; + + template bool operator==(const LiveCellRef& ref, int pRefnum); +} + +#endif diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index ea8a02dee..3338f08ed 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,14 +1,13 @@ #include "player.hpp" - #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" + +#include "../mwworld/ptr.hpp" #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" -#include "esmstore.hpp" #include "class.hpp" namespace MWWorld @@ -25,12 +24,38 @@ namespace MWWorld playerPos[0] = playerPos[1] = playerPos[2] = 0; } + void Player::setCell (MWWorld::CellStore *cellStore) + { + mCellStore = cellStore; + } + + MWWorld::Ptr Player::getPlayer() + { + MWWorld::Ptr ptr (&mPlayer, mCellStore); + return ptr; + } + + void Player::setBirthSign (const std::string &sign) + { + mSign = sign; + } + + const std::string& Player::getBirthSign() const + { + return mSign; + } + void Player::setDrawState (MWMechanics::DrawState_ state) { MWWorld::Ptr ptr = getPlayer(); MWWorld::Class::get(ptr).getNpcStats(ptr).setDrawState (state); } + bool Player::getAutoMove() const + { + return mAutoMove; + } + void Player::setAutoMove (bool enable) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index c98551091..dfaddf66a 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -1,15 +1,20 @@ #ifndef GAME_MWWORLD_PLAYER_H #define GAME_MWWORLD_PLAYER_H -#include "../mwworld/cellstore.hpp" #include "../mwworld/refdata.hpp" -#include "../mwworld/ptr.hpp" +#include "../mwworld/livecellref.hpp" #include "../mwmechanics/drawstate.hpp" +namespace ESM +{ + struct NPC; +} + namespace MWBase { class World; + class Ptr; } namespace MWWorld @@ -30,31 +35,17 @@ namespace MWWorld Player(const ESM::NPC *player, const MWBase::World& world); - void setCell (MWWorld::CellStore *cellStore) - { - mCellStore = cellStore; - } + void setCell (MWWorld::CellStore *cellStore); - MWWorld::Ptr getPlayer() - { - MWWorld::Ptr ptr (&mPlayer, mCellStore); - return ptr; - } + MWWorld::Ptr getPlayer(); - void setBirthSign(const std::string &sign) { - mSign = sign; - } + void setBirthSign(const std::string &sign); - const std::string &getBirthSign() const { - return mSign; - } + const std::string &getBirthSign() const; void setDrawState (MWMechanics::DrawState_ state); - bool getAutoMove() const - { - return mAutoMove; - } + bool getAutoMove() const; MWMechanics::DrawState_ getDrawState(); /// \todo constness From 8c7d578ddcf9a8d91e80c98618a19045252d1959 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:13:15 +0200 Subject: [PATCH 114/817] moved the CellRef struct to its own header --- apps/openmw/mwworld/livecellref.hpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/cellref.hpp | 90 +++++++++++++++++++++++++++++ components/esm/loadcell.hpp | 78 +------------------------ 4 files changed, 93 insertions(+), 79 deletions(-) create mode 100644 components/esm/cellref.hpp diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 4c5efb861..8f419b626 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWWORLD_LIVECELLREF_H #define GAME_MWWORLD_LIVECELLREF_H -#include +#include #include "refdata.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 88bf76444..a2f416fcc 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (esm loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat - loadweap records aipackage effectlist spelllist variant variantimp loadtes3 + loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref ) add_component_dir (misc diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp new file mode 100644 index 000000000..fb03a9084 --- /dev/null +++ b/components/esm/cellref.hpp @@ -0,0 +1,90 @@ +#ifndef OPENMW_ESM_CELLREF_H +#define OPENMW_ESM_CELLREF_H + +#include + +#include "defs.hpp" + +namespace ESM +{ + class ESMWriter; + + /* Cell reference. This represents ONE object (of many) inside the + cell. The cell references are not loaded as part of the normal + loading process, but are rather loaded later on demand when we are + setting up a specific cell. + */ + + class CellRef + { + public: + + int mRefnum; // Reference number + std::string mRefID; // ID of object being referenced + + float mScale; // Scale applied to mesh + + // The NPC that owns this object (and will get angry if you steal + // it) + std::string mOwner; + + // I have no idea, looks like a link to a global variable? + std::string mGlob; + + // ID of creature trapped in this soul gem (?) + std::string mSoul; + + // ?? CNAM has a faction name, might be for objects/beds etc + // belonging to a faction. + std::string mFaction; + + // INDX might be PC faction rank required to use the item? Sometimes + // is -1, which I assume means "any rank". + int mFactIndex; + + // For weapon or armor, this is the remaining item health. + // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + int mCharge; + + // Remaining enchantment charge + float mEnchantmentCharge; + + // This is 5 for Gold_005 references, 100 for Gold_100 and so on. + int mGoldValue; + + // For doors - true if this door teleports to somewhere else, false + // if it should open through animation. + bool mTeleport; + + // Teleport location for the door, if this is a teleporting door. + Position mDoorDest; + + // Destination cell for doors (optional) + std::string mDestCell; + + // Lock level for doors and containers + int mLockLevel; + std::string mKey, mTrap; // Key and trap ID names, if any + + // This corresponds to the "Reference Blocked" checkbox in the construction set, + // which prevents editing that reference. + // -1 is not blocked, otherwise it is blocked. + signed char mReferenceBlocked; + + // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. + int mDeleted; + + // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza + // Brindisi Dorom", where it has the value 100. Also only for + // activators. + int mFltv; + int mNam0; + + // Position and rotation of this object within the cell + Position mPos; + + void save(ESMWriter &esm); + }; +} + +#endif \ No newline at end of file diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index afc953f54..44412b5eb 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -7,95 +7,19 @@ #include "esmcommon.hpp" #include "defs.hpp" - +#include "cellref.hpp" namespace MWWorld { class ESMStore; } - namespace ESM { class ESMReader; class ESMWriter; -/* Cell reference. This represents ONE object (of many) inside the - cell. The cell references are not loaded as part of the normal - loading process, but are rather loaded later on demand when we are - setting up a specific cell. - */ -class CellRef -{ -public: - int mRefnum; // Reference number - std::string mRefID; // ID of object being referenced - - float mScale; // Scale applied to mesh - - // The NPC that owns this object (and will get angry if you steal - // it) - std::string mOwner; - - // I have no idea, looks like a link to a global variable? - std::string mGlob; - - // ID of creature trapped in this soul gem (?) - std::string mSoul; - - // ?? CNAM has a faction name, might be for objects/beds etc - // belonging to a faction. - std::string mFaction; - - // INDX might be PC faction rank required to use the item? Sometimes - // is -1, which I assume means "any rank". - int mFactIndex; - - // For weapon or armor, this is the remaining item health. - // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - int mCharge; - - // Remaining enchantment charge - float mEnchantmentCharge; - - // This is 5 for Gold_005 references, 100 for Gold_100 and so on. - int mGoldValue; - - // For doors - true if this door teleports to somewhere else, false - // if it should open through animation. - bool mTeleport; - - // Teleport location for the door, if this is a teleporting door. - Position mDoorDest; - - // Destination cell for doors (optional) - std::string mDestCell; - - // Lock level for doors and containers - int mLockLevel; - std::string mKey, mTrap; // Key and trap ID names, if any - - // This corresponds to the "Reference Blocked" checkbox in the construction set, - // which prevents editing that reference. - // -1 is not blocked, otherwise it is blocked. - signed char mReferenceBlocked; - - // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. - int mDeleted; - - // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza - // Brindisi Dorom", where it has the value 100. Also only for - // activators. - int mFltv; - int mNam0; - - // Position and rotation of this object within the cell - Position mPos; - - void save(ESMWriter &esm); -}; - /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another plugin tries to move it independently. From 5244362fba72d6e47e54a75b9d6a5e890d8bb266 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:23:06 +0200 Subject: [PATCH 115/817] some cleanup --- apps/openmw/mwworld/cellstore.hpp | 1 - apps/openmw/mwworld/livecellref.hpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 0cc111cde..7e4fc407d 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,7 +9,6 @@ #include "livecellref.hpp" #include "esmstore.hpp" -struct C; namespace MWWorld { diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 8f419b626..28c1bb5c2 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -39,7 +39,7 @@ namespace MWWorld RefData mData; }; - template bool operator==(const LiveCellRef& ref, int pRefnum); +// template bool operator==(const LiveCellRef& ref, int pRefnum); } #endif From 111ebf84bb352072e60cc94e7e7427872b66aa91 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:27:57 +0200 Subject: [PATCH 116/817] replaced an include with a forward declaration --- apps/openmw/mwscript/locals.cpp | 13 ++++++++----- apps/openmw/mwscript/locals.hpp | 10 +++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 2cf2a97c1..180a2791b 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -1,8 +1,11 @@ #include "locals.hpp" +#include + +#include + #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" -#include namespace MWScript { @@ -39,9 +42,9 @@ namespace MWScript } return 0; } - + bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) - { + { Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -51,10 +54,10 @@ namespace MWScript { case 's': mShorts.at (index) = val; break; - + case 'l': mLongs.at (index) = val; break; - + case 'f': mFloats.at (index) = val; break; } diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index 1d9b9c3e4..deae0d44e 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -3,9 +3,13 @@ #include -#include #include +namespace ESM +{ + struct Script; +} + namespace MWScript { class Locals @@ -14,11 +18,11 @@ namespace MWScript std::vector mShorts; std::vector mLongs; std::vector mFloats; - + void configure (const ESM::Script& script); bool setVarByInt(const std::string& script, const std::string& var, int val); int getIntVar (const std::string& script, const std::string& var); ///< if var does not exist, returns 0 - + }; } From 62d70f17c859977ac631378595cdf09b18022258 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:42:38 +0200 Subject: [PATCH 117/817] removed another redundant include --- apps/openmw/mwworld/cellstore.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 7e4fc407d..f8467c84f 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWWORLD_CELLSTORE_H #define GAME_MWWORLD_CELLSTORE_H -#include - #include #include From 18e046e6285f41b588fba796da123a44faffeae0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 13:50:36 +0200 Subject: [PATCH 118/817] cleaned up race record struct --- apps/esmtool/record.cpp | 60 ++++++------------- .../mwmechanics/mechanicsmanagerimp.cpp | 16 +---- components/esm/loadrace.cpp | 9 +++ components/esm/loadrace.hpp | 13 ++-- 4 files changed, 34 insertions(+), 64 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index d15e7f2b0..a6f77862e 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1099,53 +1099,29 @@ void Record::print() template<> void Record::print() { + static const char *sAttributeNames[8] = + { + "Strength", "Intelligence", "Willpower", "Agility", + "Speed", "Endurance", "Personality", "Luck" + }; + std::cout << " Name: " << mData.mName << std::endl; std::cout << " Description: " << mData.mDescription << std::endl; std::cout << " Flags: " << raceFlags(mData.mData.mFlags) << std::endl; - std::cout << " Male:" << std::endl; - std::cout << " Strength: " - << mData.mData.mStrength.mMale << std::endl; - std::cout << " Intelligence: " - << mData.mData.mIntelligence.mMale << std::endl; - std::cout << " Willpower: " - << mData.mData.mWillpower.mMale << std::endl; - std::cout << " Agility: " - << mData.mData.mAgility.mMale << std::endl; - std::cout << " Speed: " - << mData.mData.mSpeed.mMale << std::endl; - std::cout << " Endurance: " - << mData.mData.mEndurance.mMale << std::endl; - std::cout << " Personality: " - << mData.mData.mPersonality.mMale << std::endl; - std::cout << " Luck: " - << mData.mData.mLuck.mMale << std::endl; - std::cout << " Height: " - << mData.mData.mHeight.mMale << std::endl; - std::cout << " Weight: " - << mData.mData.mWeight.mMale << std::endl; + for (int i=0; i<2; ++i) + { + bool male = i==0; - std::cout << " Female:" << std::endl; - std::cout << " Strength: " - << mData.mData.mStrength.mFemale << std::endl; - std::cout << " Intelligence: " - << mData.mData.mIntelligence.mFemale << std::endl; - std::cout << " Willpower: " - << mData.mData.mWillpower.mFemale << std::endl; - std::cout << " Agility: " - << mData.mData.mAgility.mFemale << std::endl; - std::cout << " Speed: " - << mData.mData.mSpeed.mFemale << std::endl; - std::cout << " Endurance: " - << mData.mData.mEndurance.mFemale << std::endl; - std::cout << " Personality: " - << mData.mData.mPersonality.mFemale << std::endl; - std::cout << " Luck: " - << mData.mData.mLuck.mFemale << std::endl; - std::cout << " Height: " - << mData.mData.mHeight.mFemale << std::endl; - std::cout << " Weight: " - << mData.mData.mWeight.mFemale << std::endl; + std::cout << (male ? " Male:" : " Female:") << std::endl; + + for (int i=0; i<8; ++i) + std::cout << " " << sAttributeNames[i] << ": " + << mData.mData.mAttributeValues[i].getValue (male) << std::endl; + + std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl; + std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl; + } for (int i = 0; i != 7; i++) // Not all races have 7 skills. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c8d827921..8757213e9 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -53,21 +53,9 @@ namespace MWMechanics for (int i=0; i<8; ++i) { - const ESM::Race::MaleFemale *attribute = 0; - switch (i) - { - case 0: attribute = &race->mData.mStrength; break; - case 1: attribute = &race->mData.mIntelligence; break; - case 2: attribute = &race->mData.mWillpower; break; - case 3: attribute = &race->mData.mAgility; break; - case 4: attribute = &race->mData.mSpeed; break; - case 5: attribute = &race->mData.mEndurance; break; - case 6: attribute = &race->mData.mPersonality; break; - case 7: attribute = &race->mData.mLuck; break; - } + const ESM::Race::MaleFemale& attribute = race->mData.mAttributeValues[i]; - creatureStats.getAttribute(i).setBase ( - static_cast (male ? attribute->mMale : attribute->mFemale)); + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); } for (int i=0; i<27; ++i) diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 139ef081c..94aa792bc 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -5,6 +5,15 @@ namespace ESM { + int Race::MaleFemale::getValue (bool male) const + { + return male ? mMale : mFemale; + } + + int Race::MaleFemaleF::getValue (bool male) const + { + return male ? mMale : mFemale; + } void Race::load(ESMReader &esm) { diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 91a424c10..845956686 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -26,11 +26,15 @@ struct Race struct MaleFemale { int mMale, mFemale; + + int getValue (bool male) const; }; struct MaleFemaleF { float mMale, mFemale; + + int getValue (bool male) const; }; enum Flags @@ -45,14 +49,7 @@ struct Race SkillBonus mBonus[7]; // Attribute values for male/female - MaleFemale mStrength, - mIntelligence, - mWillpower, - mAgility, - mSpeed, - mEndurance, - mPersonality, - mLuck; + MaleFemale mAttributeValues[8]; // The actual eye level height (in game units) is (probably) given // as 'height' times 128. This has not been tested yet. From 97d617d43f0bb88d680ddab826ee158d6f73c5e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 04:33:56 -0700 Subject: [PATCH 119/817] Use more appropriate VBO settings Unskinned meshes don't need dynamic VBOs; they aren't rewritten since their transformations are handled by the modelview matrix. They also don't need the local RAM copy (the "shadow buffer") since it's really only useful for skinning purposes (though this means the VBO has to be readable for static geometry to work). --- components/nifogre/ogrenifloader.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f8eca821f..608323880 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -845,8 +845,13 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); std::vector srcVerts = data->vertices; std::vector srcNorms = data->normals; + Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; + bool vertShadowBuffer = false; if(skin != NULL) { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be // explicitly attached later. mesh->setSkeletonName(mName); @@ -948,8 +953,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcVerts.size()) { vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcVerts.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, - true); + srcVerts.size(), vertUsage, vertShadowBuffer); vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); @@ -960,8 +964,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcNorms.size()) { vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcNorms.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, - true); + srcNorms.size(), vertUsage, vertShadowBuffer); vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); @@ -980,8 +983,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader rs->convertColourValue(clr, &colorsRGB[i]); } vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, - true); + colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); bind->setBinding(nextBuf++, vbuf); @@ -993,7 +995,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size()*numUVs, - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); + Ogre::HardwareBuffer::HBU_STATIC); for(size_t i = 0;i < numUVs;i++) { const std::vector &uvlist = data->uvlist[i]; @@ -1009,7 +1011,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcIdx.size()) { ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); + Ogre::HardwareBuffer::HBU_STATIC); ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); sub->indexData->indexBuffer = ibuf; sub->indexData->indexCount = srcIdx.size(); From ee0a20f9ce30cd885a3110df97b6e911095d5d7f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 07:00:24 -0700 Subject: [PATCH 120/817] Read some missing particle data from NIFs --- components/nif/data.hpp | 13 +++++++++---- components/nif/nifstream.hpp | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 9bdba6396..68ffd19b8 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -167,6 +167,10 @@ class NiAutoNormalParticlesData : public ShapeData public: int activeCount; + float activeRadius; + + std::vector sizes; + void read(NIFStream *nif) { ShapeData::read(nif); @@ -174,14 +178,13 @@ public: // Should always match the number of vertices activeCount = nif->getUShort(); - // Skip all the info, we don't support particles yet - nif->getFloat(); // Active radius ? + activeRadius = nif->getFloat(); nif->getUShort(); // Number of valid entries in the following arrays ? if(nif->getInt()) { // Particle sizes - nif->skip(activeCount * sizeof(float)); + nif->getFloats(sizes, activeCount); } } }; @@ -189,6 +192,8 @@ public: class NiRotatingParticlesData : public NiAutoNormalParticlesData { public: + std::vector rotations; + void read(NIFStream *nif) { NiAutoNormalParticlesData::read(nif); @@ -198,7 +203,7 @@ public: // Rotation quaternions. I THINK activeCount is correct here, // but verts (vertex number) might also be correct, if there is // any case where the two don't match. - nif->skip(activeCount * 4*sizeof(float)); + nif->getQuaternions(rotations, activeCount); } } }; diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 02b931b7e..a2595d17b 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -168,6 +168,12 @@ public: for(size_t i = 0;i < vec.size();i++) vec[i] = getVector4(); } + void getQuaternions(std::vector &quat, size_t size) + { + quat.resize(size); + for(size_t i = 0;i < quat.size();i++) + quat[i] = getQuaternion(); + } }; } From 2f6ae4a915e1a26f75afd6993dd0b06ab40a211b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 20:56:35 -0700 Subject: [PATCH 121/817] Read more particle information --- components/nif/controller.hpp | 79 ++++++++++++++++++++++++++++++++--- components/nif/data.hpp | 18 ++++---- components/nif/recordptr.hpp | 1 + 3 files changed, 82 insertions(+), 16 deletions(-) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 8331b93b7..2ff25a274 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -62,20 +62,87 @@ public: } }; -class NiBSPArrayController : public Controller +class NiParticleSystemController : public Controller { public: + float velocity; + float velocityRandom; + + float verticalDir; // 0=up, pi/2=horizontal, pi=down + float verticalAngle; + float horizontalDir; + float horizontalAngle; + + float size; + float startTime; + float stopTime; + + float emitRate; + float lifetime; + float lifetimeRandom; + + int emitFlags; // Bit 0: Emit Rate toggle bit (0 = auto adjust, 1 = use Emit Rate value) + Ogre::Vector3 offsetRandom; + + NodePtr emitter; + + int numParticles; + int activeCount; + //std::vector particles; /*numParticles*/ + + RecordPtr modifier; + void read(NIFStream *nif) { Controller::read(nif); - // At the moment, just skip it all - nif->skip(111); - int s = nif->getUShort(); - nif->skip(15 + s*40); + velocity = nif->getFloat(); + velocityRandom = nif->getFloat(); + verticalDir = nif->getFloat(); + verticalAngle = nif->getFloat(); + horizontalDir = nif->getFloat(); + horizontalAngle = nif->getFloat(); + /*normal?*/ nif->getVector3(); + /*color?*/ nif->getVector4(); + size = nif->getFloat(); + startTime = nif->getFloat(); + stopTime = nif->getFloat(); + nif->getChar(); + emitRate = nif->getFloat(); + lifetime = nif->getFloat(); + lifetimeRandom = nif->getFloat(); + + emitFlags = nif->getUShort(); + offsetRandom = nif->getVector3(); + + emitter.read(nif); + + /* Unknown Short, 0? + * Unknown Float, 1.0? + * Unknown Int, 1? + * Unknown Int, 0? + * Unknown Short, 0? + */ + nif->skip(16); + + numParticles = nif->getUShort(); + activeCount = nif->getUShort(); + nif->skip(numParticles*40); + + nif->getUInt(); /* -1? */ + modifier.read(nif); + nif->getUInt(); /* -1? */ + nif->getChar(); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + emitter.post(nif); + modifier.post(nif); } }; -typedef NiBSPArrayController NiParticleSystemController; +typedef NiParticleSystemController NiBSPArrayController; class NiMaterialColorController : public Controller { diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 68ffd19b8..a2c9bb56d 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -165,9 +165,9 @@ public: class NiAutoNormalParticlesData : public ShapeData { public: - int activeCount; + float particleSize; - float activeRadius; + int activeCount; std::vector sizes; @@ -176,15 +176,15 @@ public: ShapeData::read(nif); // Should always match the number of vertices - activeCount = nif->getUShort(); + nif->getUShort(); - activeRadius = nif->getFloat(); - nif->getUShort(); // Number of valid entries in the following arrays ? + particleSize = nif->getFloat(); + activeCount = nif->getUShort(); if(nif->getInt()) { // Particle sizes - nif->getFloats(sizes, activeCount); + nif->getFloats(sizes, vertices.size()); } } }; @@ -200,10 +200,8 @@ public: if(nif->getInt()) { - // Rotation quaternions. I THINK activeCount is correct here, - // but verts (vertex number) might also be correct, if there is - // any case where the two don't match. - nif->getQuaternions(rotations, activeCount); + // Rotation quaternions. + nif->getQuaternions(rotations, vertices.size()); } } }; diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index c5bafea12..b7cd122bc 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -142,6 +142,7 @@ class NiSourceTexture; class NiRotatingParticlesData; class NiAutoNormalParticlesData; +typedef RecordPtrT RecordPtr; typedef RecordPtrT NodePtr; typedef RecordPtrT ExtraPtr; typedef RecordPtrT NiUVDataPtr; From ac10c5f05cd94034d3ee6b4a0ed97dc9518a8fc9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 01:26:57 -0700 Subject: [PATCH 122/817] Even more particle information --- components/nif/controlled.hpp | 8 +++++--- components/nif/controller.hpp | 29 ++++++++++++++++++++++++----- components/nif/recordptr.hpp | 1 - 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 36c9a82ac..08c47defe 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -66,12 +66,14 @@ typedef Named NiSequenceStreamHelper; class NiParticleGrowFade : public Controlled { public: + float growTime; + float fadeTime; + void read(NIFStream *nif) { Controlled::read(nif); - - // Two floats. - nif->skip(8); + growTime = nif->getFloat(); + fadeTime = nif->getFloat(); } }; diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 2ff25a274..aa6a9ef4f 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -65,6 +65,14 @@ public: class NiParticleSystemController : public Controller { public: + struct Particle { + Ogre::Vector3 velocity; + float lifetime; + float lifespan; + float timestamp; + int vertex; + }; + float velocity; float velocityRandom; @@ -88,9 +96,9 @@ public: int numParticles; int activeCount; - //std::vector particles; /*numParticles*/ + std::vector particles; - RecordPtr modifier; + ExtraPtr extra; void read(NIFStream *nif) { @@ -127,10 +135,21 @@ public: numParticles = nif->getUShort(); activeCount = nif->getUShort(); - nif->skip(numParticles*40); + + particles.resize(numParticles); + for(size_t i = 0;i < particles.size();i++) + { + particles[i].velocity = nif->getVector3(); + nif->getVector3(); /* unknown */ + particles[i].lifetime = nif->getFloat(); + particles[i].lifespan = nif->getFloat(); + particles[i].timestamp = nif->getFloat(); + nif->getUShort(); /* unknown */ + particles[i].vertex = nif->getUShort(); + } nif->getUInt(); /* -1? */ - modifier.read(nif); + extra.read(nif); nif->getUInt(); /* -1? */ nif->getChar(); } @@ -139,7 +158,7 @@ public: { Controller::post(nif); emitter.post(nif); - modifier.post(nif); + extra.post(nif); } }; typedef NiParticleSystemController NiBSPArrayController; diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index b7cd122bc..c5bafea12 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -142,7 +142,6 @@ class NiSourceTexture; class NiRotatingParticlesData; class NiAutoNormalParticlesData; -typedef RecordPtrT RecordPtr; typedef RecordPtrT NodePtr; typedef RecordPtrT ExtraPtr; typedef RecordPtrT NiUVDataPtr; From 77ba0fbe730ff6d9e7a20126df177054d183eed2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 01:31:05 -0700 Subject: [PATCH 123/817] Prepare for creating particles This adds a vector of ParticleSystems to the EntityList, and modifies corresponding code to handle it. It also loads the ParticleFX plugin so particles can be created (although they aren't yet). --- apps/openmw/mwrender/animation.cpp | 3 +++ apps/openmw/mwrender/npcanimation.cpp | 6 +++--- apps/openmw/mwrender/objects.cpp | 13 ++++++++++++- components/nifogre/ogrenifloader.hpp | 4 +++- libs/openengine/ogre/renderer.cpp | 1 + 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cc926e685..fd575f918 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -40,9 +40,12 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < mEntityList.mParticles.size();i++) + sceneMgr->destroyParticleSystem(mEntityList.mParticles[i]); for(size_t i = 0;i < mEntityList.mEntities.size();i++) sceneMgr->destroyEntity(mEntityList.mEntities[i]); } + mEntityList.mParticles.clear(); mEntityList.mEntities.clear(); mEntityList.mSkelBase = NULL; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b76a38c46..f1af6a7d3 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -363,11 +363,11 @@ void NpcAnimation::removeEntities(NifOgre::EntityList &entities) assert(&entities != &mEntityList); Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < entities.mParticles.size();i++) + sceneMgr->destroyParticleSystem(entities.mParticles[i]); for(size_t i = 0;i < entities.mEntities.size();i++) - { - entities.mEntities[i]->detachFromParent(); sceneMgr->destroyEntity(entities.mEntities[i]); - } + entities.mParticles.clear(); entities.mEntities.clear(); entities.mSkelBase = NULL; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 50c021064..8c5d4cad3 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -156,7 +158,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool } } - if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || anyTransparency) + if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || + anyTransparency || entities.mParticles.size() > 0) { for(size_t i = 0;i < entities.mEntities.size();i++) { @@ -169,6 +172,14 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } + for(size_t i = 0;i < entities.mParticles.size();i++) + { + Ogre::ParticleSystem *part = entities.mParticles[i]; + // TODO: Check the particle system's material for actual transparency + part->setRenderQueueGroup(RQG_Alpha); + part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); + part->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); + } } else { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 92b153468..e6672541b 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -40,8 +40,10 @@ namespace NifOgre typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { - std::vector mEntities; Ogre::Entity *mSkelBase; + std::vector mEntities; + + std::vector mParticles; EntityList() : mSkelBase(0) { } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 309ba8a06..05760ffa9 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -195,6 +195,7 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); + Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) From b5719e0ec7051d139de32023577c630124842c9f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 05:08:12 -0700 Subject: [PATCH 124/817] Create particle systems for NiAutoNormalParticles and NiRotatingParticles nodes Very incomplete, but it's something to work with. --- components/nifogre/ogrenifloader.cpp | 171 +++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 608323880..6d08d4ffc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -317,7 +319,9 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ - node->recType == Nif::RC_NiTriShape /* Handled in the mesh loader */ + node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); @@ -326,7 +330,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); - else + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController + )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } @@ -588,7 +593,8 @@ static std::string findTextureName(const std::string &filename) } public: -static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, +static Ogre::String getMaterial(const Nif::ShapeData *shapedata, + const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, @@ -617,7 +623,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int specFlags = 0; Ogre::String texName[7]; - bool vertexColour = (shape->data->colors.size() != 0); + bool vertexColour = (shapedata->colors.size() != 0); // Texture if(texprop) @@ -819,12 +825,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mGroup; size_t mShapeIndex; - void warn(const std::string &msg) + static void warn(const std::string &msg) { std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; } - void fail(const std::string &msg) + static void fail(const std::string &msg) { std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; abort(); @@ -1039,9 +1045,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } bool needTangents=false; - std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup, + std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, - vertprop, zprop, specprop, needTangents); + vertprop, zprop, specprop, + needTangents); if(matname.length() > 0) sub->setMaterialName(matname); @@ -1114,6 +1121,146 @@ class NIFMeshLoader : Ogre::ManualResourceLoader static LoaderMap sLoaders; + static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) + { + Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); + emitter->setDirection(Ogre::Vector3::UNIT_Z); + emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, + partctrl->velocity+partctrl->velocityRandom); + emitter->setEmissionRate(partctrl->emitRate); + emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, + partctrl->lifetime+partctrl->lifetimeRandom); + + Nif::ExtraPtr e = partctrl->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiParticleGrowFade) + { + // TODO: Implement + } + else if(e->recType == Nif::RC_NiParticleColorModifier) + { + // TODO: Implement (Ogre::ColourInterpolatorAffector?) + } + else if(e->recType == Nif::RC_NiGravity) + { + // TODO: Implement (Ogre::LinearForceAffector?) + } + else + warn("Unhandled particle modifier "+e->recName); + e = e->extra; + } + } + + Ogre::ParticleSystem *createParticleSystem(Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, + const Nif::Node *partnode) + { + const Nif::NiAutoNormalParticlesData *particledata = NULL; + if(partnode->recType == Nif::RC_NiAutoNormalParticles) + particledata = static_cast(partnode)->data.getPtr(); + else if(partnode->recType == Nif::RC_NiRotatingParticles) + particledata = static_cast(partnode)->data.getPtr(); + + Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); + try { + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + if(partnode->parent) + { + // FIXME: We should probably search down the whole tree instead of just the parent + const Nif::PropertyList &proplist = partnode->parent->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + } + const Nif::PropertyList &proplist = partnode->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + + std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + + bool needTangents; + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + needTangents)); + + partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); + partsys->setCullIndividually(false); + partsys->setParticleQuota(particledata->activeCount); + + Nif::ControllerPtr ctrl = partnode->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiParticleSystemController) + { + const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); + + createParticleEmitterAffectors(partsys, partctrl); + if(!partctrl->emitter.empty() && !partsys->isAttached()) + entitybase->attachObjectToBone(partctrl->emitter->name, partsys); + } + ctrl = ctrl->next; + } + + if(!partsys->isAttached()) + entitybase->attachObjectToBone(partnode->name, partsys); + } + catch(std::exception &e) { + std::cerr<< "Particles exception: "<destroyParticleSystem(partsys); + partsys = NULL; + }; + return partsys; + } + + NIFMeshLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1199,6 +1346,14 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } + if((node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x01)) + { + Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); + if(partsys != NULL) + entities.mParticles.push_back(partsys); + } + const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { From 73da794d77c8d2552bf478478f43b54e4c45d028 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 14:34:39 +0200 Subject: [PATCH 125/817] added basic race table --- apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadrace.cpp | 21 +++++++++++++++++++++ components/esm/loadrace.hpp | 3 +++ 9 files changed, 64 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d62fd7267..c596bb162 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -66,11 +66,17 @@ CSMWorld::Data::Data() for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); + mRaces.addColumn (new StringIdColumn); + mRaces.addColumn (new RecordStateColumn); + mRaces.addColumn (new NameColumn); + mRaces.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); + addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); } CSMWorld::Data::~Data() @@ -129,6 +135,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getFactions() return mFactions; } +const CSMWorld::IdCollection& CSMWorld::Data::getRaces() const +{ + return mRaces; +} + +CSMWorld::IdCollection& CSMWorld::Data::getRaces() +{ + return mRaces; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -168,6 +184,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SKIL: mSkills.load (reader, base); break; case ESM::REC_CLAS: mClasses.load (reader, base); break; case ESM::REC_FACT: mFactions.load (reader, base); break; + case ESM::REC_RACE: mRaces.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 16a9685a5..6b729728f 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -26,6 +27,7 @@ namespace CSMWorld IdCollection mSkills; IdCollection mClasses; IdCollection mFactions; + IdCollection mRaces; std::vector mModels; std::map mModelIndex; @@ -62,6 +64,10 @@ namespace CSMWorld IdCollection& getFactions(); + const IdCollection& getRaces() const; + + IdCollection& getRaces(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 985cab0d4..2e5e6a0a0 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -22,6 +22,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -33,6 +34,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 0190467c4..2213e15f3 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -43,7 +43,9 @@ namespace CSMWorld Type_Classes, Type_Class, Type_Factions, - Type_Faction + Type_Faction, + Type_Races, + Type_Race }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 83b333c04..e12929cf2 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -101,6 +101,10 @@ void CSVDoc::View::setupWorldMenu() QAction *factions = new QAction (tr ("Factions"), this); connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); world->addAction (factions); + + QAction *races = new QAction (tr ("Races"), this); + connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView())); + world->addAction (races); } void CSVDoc::View::setupUi() @@ -271,6 +275,11 @@ void CSVDoc::View::addFactionsSubView() addSubView (CSMWorld::UniversalId::Type_Factions); } +void CSVDoc::View::addRacesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Races); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 03905430a..4132d73b2 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -121,6 +121,8 @@ namespace CSVDoc void addClassesSubView(); void addFactionsSubView(); + + void addRacesSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index de36594a5..d5ba27377 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -19,6 +19,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Globals, CSMWorld::UniversalId::Type_Classes, CSMWorld::UniversalId::Type_Factions, + CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 94aa792bc..955424e2b 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -30,4 +30,25 @@ void Race::save(ESMWriter &esm) esm.writeHNOString("DESC", mDescription); } + void Race::blank() + { + mName.clear(); + mDescription.clear(); + + mPowers.mList.clear(); + + for (int i=0; i<7; ++i) + { + mData.mBonus[i].mSkill = -1; + mData.mBonus[i].mBonus = 0; + } + + for (int i=0; i<8; ++i) + mData.mAttributeValues[i].mMale = mData.mAttributeValues[i].mFemale = 1; + + mData.mHeight.mMale = mData.mHeight.mFemale = 1; + mData.mWeight.mMale = mData.mWeight.mFemale = 1; + + mData.mFlags = 0; + } } diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 845956686..6ecec8ebb 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -66,6 +66,9 @@ struct Race void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } From 48a88f1917d00eccb9c2e490f13f3dc335c240be Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Apr 2013 15:10:27 +0200 Subject: [PATCH 126/817] Fix startRandomTitle --- apps/openmw/mwsound/soundmanagerimp.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1b07dfe62..69e301676 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -208,14 +208,21 @@ namespace MWSound void SoundManager::startRandomTitle() { - Ogre::StringVectorPtr filelist; - filelist = mResourceMgr.findResourceNames(Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "Music/"+mCurrentPlaylist+"/*"); - if(!filelist->size()) + Ogre::StringVector filelist; + + Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); + for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + { + Ogre::StringVectorPtr resourcesInThisGroup = mResourceMgr.findResourceNames(*it, + "Music/"+mCurrentPlaylist+"/*"); + filelist.insert(filelist.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); + } + + if(!filelist.size()) return; - int i = rand()%filelist->size(); - streamMusicFull((*filelist)[i]); + int i = rand()%filelist.size(); + streamMusicFull(filelist[i]); } bool SoundManager::isMusicPlaying() From 2e7d5377f40b257186f21e939e370e298c5b51f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Apr 2013 16:51:22 +0200 Subject: [PATCH 127/817] Fix crash when moving npcs to an inactive cell --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- .../mwscript/transformationextensions.cpp | 4 ++-- apps/openmw/mwworld/scene.cpp | 14 +++++------ apps/openmw/mwworld/worldimp.cpp | 24 ++++++++++++++----- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2f49a4031..cd5ab19b9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -235,7 +235,7 @@ void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) mObjects.buildStaticGeometry (*store); mDebugging->cellAdded(store); if (store->mCell->isExterior()) - mTerrainManager->cellAdded(store); + mTerrainManager->cellAdded(store); waterAdded(store); } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 000cc545d..97dc6d718 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -304,7 +304,7 @@ namespace MWScript } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); - MWBase::Environment::get().getWorld()->adjustPosition(ptr); + MWWorld::Class::get(ptr).adjustPosition(ptr); } else { @@ -343,7 +343,7 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); - MWBase::Environment::get().getWorld()->adjustPosition(ptr); + MWWorld::Class::get(ptr).adjustPosition(ptr); } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c8853f484..2244a4fc6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -115,11 +115,6 @@ namespace MWWorld if(result.second) { - /// \todo rescale depending on the state of a new GMST - insertCell (*cell, true); - - mRendering.cellAdded (cell); - float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; @@ -142,6 +137,11 @@ namespace MWWorld } } + /// \todo rescale depending on the state of a new GMST + insertCell (*cell, true); + + mRendering.cellAdded (cell); + mRendering.configureAmbient(*cell); mRendering.requestMap(cell); mRendering.configureAmbient(*cell); @@ -166,7 +166,7 @@ namespace MWWorld float z = Ogre::Radian(pos.rot[2]).valueDegrees(); world->rotateObject(player, x, y, z); - world->adjustPosition(player); + MWWorld::Class::get(player).adjustPosition(player); } MWBase::MechanicsManager *mechMgr = @@ -358,7 +358,7 @@ namespace MWWorld float z = Ogre::Radian(position.rot[2]).valueDegrees(); world->rotateObject(world->getPlayer().getPlayer(), x, y, z); - world->adjustPosition(world->getPlayer().getPlayer()); + MWWorld::Class::get(world->getPlayer().getPlayer()).adjustPosition(world->getPlayer().getPlayer()); return; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2ce753b81..ae9b7a06b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -706,6 +706,7 @@ namespace MWWorld void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { ESM::Position &pos = ptr.getRefData().getPosition(); + pos.pos[0] = x; pos.pos[1] = y; pos.pos[2] = z; @@ -718,7 +719,7 @@ namespace MWWorld if (*currCell != newCell) { - removeContainerScripts(ptr); + removeContainerScripts(ptr); if (isPlayer) { @@ -750,7 +751,7 @@ namespace MWWorld else { MWWorld::Ptr copy = - MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + MWWorld::Class::get(ptr).copyToCell(ptr, newCell, pos); mRendering->updateObjectCell(ptr, copy); @@ -780,12 +781,14 @@ namespace MWWorld bool World::moveObjectImp(const Ptr& ptr, float x, float y, float z) { CellStore *cell = ptr.getCell(); + if (cell->isExterior()) { int cellX, cellY; positionToIndex(x, y, cellX, cellY); cell = getExterior(cellX, cellY); } + moveObject(ptr, *cell, x, y, z); return cell != ptr.getCell(); @@ -827,6 +830,19 @@ namespace MWWorld { Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); + if(!ptr.getRefData().getBaseNode()) + { + // will be adjusted when Ptr's cell becomes active + return; + } + + float terrainHeight = mRendering->getTerrainHeightAt(pos); + + if (pos.z < terrainHeight) + pos.z = terrainHeight+400; // place slightly above. will snap down to ground with code below + + ptr.getRefData().getPosition().pos[2] = pos.z; + if (!isFlying(ptr)) { Ogre::Vector3 traced = mPhysics->traceDown(ptr); @@ -834,10 +850,6 @@ namespace MWWorld pos.z = traced.z; } - float terrainHeight = mRendering->getTerrainHeightAt(pos); - if (pos.z < terrainHeight) - pos.z = terrainHeight; - moveObject(ptr, pos.x, pos.y, pos.z); } From 01314b7c08e25ca4376e38bb97fc148e0217a208 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 5 Apr 2013 12:08:35 +0200 Subject: [PATCH 128/817] addin more nomadic icons --- files/opencs/raster/activator.png | Bin 0 -> 2297 bytes files/opencs/raster/apparatus.png | Bin 1864 -> 1580 bytes files/opencs/raster/creature.png | Bin 0 -> 2506 bytes files/opencs/raster/leveled-creature.png | Bin 0 -> 2212 bytes files/opencs/raster/lockpick.png | Bin 0 -> 679 bytes files/opencs/raster/probe.png | Bin 0 -> 583 bytes files/opencs/raster/random-item.png | Bin 1612 -> 1993 bytes files/opencs/raster/repair.png | Bin 1474 -> 1280 bytes files/opencs/scalable/top-level/.directory | 5 + files/opencs/scalable/top-level/gmst.svg | 1047 +++++++++++++++++ .../scalable/top-level/topic-regular.svg | 1045 ++++++++++++++++ 11 files changed, 2097 insertions(+) create mode 100644 files/opencs/raster/activator.png create mode 100644 files/opencs/raster/creature.png create mode 100644 files/opencs/raster/leveled-creature.png create mode 100644 files/opencs/raster/lockpick.png create mode 100644 files/opencs/raster/probe.png create mode 100644 files/opencs/scalable/top-level/.directory create mode 100644 files/opencs/scalable/top-level/gmst.svg create mode 100644 files/opencs/scalable/top-level/topic-regular.svg diff --git a/files/opencs/raster/activator.png b/files/opencs/raster/activator.png new file mode 100644 index 0000000000000000000000000000000000000000..0446af22cf7d4238e06d7682ab5ec86127b103c8 GIT binary patch literal 2297 zcmZ{lX*ARi7sr2+b!?S2`22n@r05bxw9> z^a&3Bmx+@u2Id9;@G%8)gk@vqEIv0)41tP1iIu;TIOI)p00=$@0Fguh_{}UuE(3rc z2mq^20HB=-03u$wjn;5xgZ;jl34%$c9T+u5Fu~=8wDV!EKK$z}kN}Mw0O06FAq;FW zly$VLSNgD6cnjljqh$tyiWEP+dLoMS><*1|p{VYgzjG-~6k=+-Tw27pJha7ule}iJ zCjHo-@1Xm~92G#P9X3(>6-s7(vyD7E^(R zY|+H&S)R1roK?+@EQ}5zxj=k?*TJtLS8B4(0LhYFtdwhEGFBDkQ_??mI8^AuH!gID4Sc&3jLI6eP)tANo{PpG~ zaSm&o4Q=0&PfBZ$R67^YrGvI?xmQh7k17<5#{Iyk(x-J43&iRoQPZs6|=c~?~hpWO<)=%C!K4rHq0*w?(Z zOC7`(HWg9=q|J4gPT|rJLH50I$Zb{m>(J6qH** z;dZl6nk-)HhLtzN`6@^G<#C2L5n2$7PHJ~2W*Llvw0!=N3Xu)rCJ08YJdw$~&q&n8!U7?6S7tH0Um~iLog$FC%$~rzyzd zvfo@`qXO`LBSGVy1fHixQF0gKQWA`A32wqu($dlna2G#U{+w+3Gq%HBBl(zo13KOf z-l!a1;>{F0!(a^q%~^@37a&2P)2x5U9HHq{5;3eeD+()`F}UbtW=56ai4&d2AiepB z0wfp*>a=P(j4yAAP{>$tIkrk|l;De4)8qFz(Q@?cc)uh-_?hU{LPXkv(j{s%c6C{L zIR?AjlX|22uF3}(;Pc|wj0|D=?=wHA#-~&t4V8|3CJ3dl%myEZyjlBQ+g`Xb z;3p||IVMz>-}HQ`Lu6ZGDuU~^h_-l8o=9|iTO2|z%dF(v;cE+%hIucUFb$8ron7f$ z5~lHmP`>0ve|NWu@53V#4+Jkpka>lkP8py7A|4y%eg!h9Ua-cl?9l9-do5%mzS^bF z1C8d5eJqpnMK((!5^oJkOpf|*ZhD4Pgktlw2;QqSh?}%JPxWwN-IuMS|CB^n2h7Cp z_RnlIe0#S(-Smh4XGdaiY{)ABwbH{Mde5LDG*b*3jK=LyH9C*t;xzfVQ@FPv-tI1rlDjxq?EYBlwLw^!DnfrR@Cm1rW$W&R2uH zttxR3)!8%fUyoNlrYE|+g0B*SHCvnK(~IZ0>vcJ99R)9Pbk!=LWFw=BT^W2`26E3u z4GTb+=~JG;p}>3kGNR=`U*p);x$u7SzN{B|&UTv!R-76axHpn}NnkM0Q?fX+!N&7}ZvfUC4+I1RD7!v(^TA=g@XDUvE;$?Uv& literal 0 HcmV?d00001 diff --git a/files/opencs/raster/apparatus.png b/files/opencs/raster/apparatus.png index 613030267620c5a7680dec1cacb012a6cdc7e5d7..037ed290fe9d5fd538bd21f9eda35f83d5048069 100644 GIT binary patch delta 1547 zcmV+m2K4#J4y+82Bnkm@Qb$4nuFf3kks%X*32;bRa{vGf5&!@T5&_cPe*6Fc02*{f zSaefwW^{L9a%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000G>Nkl%ilj80$5+v+~wjEsV4FD4J??VGdK*?aA^_Q(5j)v7OKfud=nF?3F;5SIhs zdGhdrm6GzZvYqJdJ&D9b{hP3LG9Ql;2n-O_H#X*Dc6JzN&lW+Yl8$(k0JR_`FE0ag zbGPvDp##au5q~L_VzZ}6@Q46EEiGn$c6_`G&!11gYAu8+STgG|0t`r}Q%u`zHB^QB zxOJ-o+qat$tn@GR1PM;@^x_ewgX!r}+`n%_eSI!fLHviu2n5MQ*5cwUJb2*1Cci$wpW#k+5uxz{aF-ByBKY!+Jf| z(@9L!!EDyToS;F1Nexqc7~k!NT61W!S`MBnrAX;U6(Ickox;*1bcArUN@L2-M-z4v9WfH zj$XjXNGl2S9JS^w3A70V17~pcY6EPxQtoZ7{rn7#bbBfCey*|g>6rjXD0x_GgFv0*MYa;)r5r`_!@ zXW%DK{)(KOjgSWsfpCLzj){=<-08gP*0R3^KYsidWM^-HRO&s)1rh7b%*^j3uaOje>z#P9Z#N&xkYeG!AnbjKth5HLcy9^wvencnbZq? zeKp*ujgMdctZH9>3SL(BBlhgEkN|xa81~yVoMIocICeU(eYR2i5ID=1j0_zFe6J~% z#2f*I+~53dY9!5b6=yPIW1atd&Q}6wuMZ0ofY0~h_RhsH68rm37Zqia;k0oM$0GT^ zn#@YzhYn>@<|yIqy?XlXwzWurc0eDMN<3dt@iPgLxnM7U?DkXt+Tm6LFDc1FW~Lq@ z(VBUoz-#f};JL6ehi$AomBeu0`-2!ySwJH-!MPX z+IkkLOszvhRxVh2da6I^?Vkdd2YJK$o7MG87v1*=u>VA*!f!q;EdslDuSY>aIz?>_ zmuf6-R|=MYkM(@>W)1BW0nqD(WISH;3}eL#goKDUF>sdY4##PV&U%W@TFU+=E>gR@ ztCpqOhrlZx2US(s+;YpTmpw+K@r6j}wP{5HfdPE8#iFG+Jw{6@d-3vRf?dwq z!{+(Ok?(Q%@HQ}Y7Zz^eK=Si9p}2S(*hC#XxCIAx4y1G0zjJ2-LPOWWXYK0ue*2bb zKq~QllbWhS3hjaxi<;K7FeD|dqZKWLN~xmtESPLmiTHRqt!6>AmdOwk9e}7PDU3!5 xtz%+Z#r$9}h`6%rw0!R6YPAmof3s8re*;>O4EKC1no$4%002ovPDHLkV1nah delta 1849 zcmV-92gdlU49E_UB!2{FK}|sb0I`n?{9y$E0004VQb$4nuFf3k0000WV@Og>004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv00000008+zyMF)x z010qNS#tmY4f_B94f_ELcQu;;00tOIL_t(o!@ZVmh+J10$AACl<=&Z{$?QzBlV)}{ zBu&T*DQSF3X(0Vz(nb-*60{mbD3q28C5t3bKZzhg@rw{@G6XD$_#wz*P}?YBD~Qw} zwhKzl+E(H=-DbPHnH^_$cJ}VQ=bY#9!@YN$jM?1@*dBPeGw0kn|KIa}o_p>HY%pG} z)wZ^c*+R?}Eq~?qxkh6!tM$lo5M+c9^IM087Ja4W9q^$977DrCd!K*qIlIxm=@4rz zymIN%(e~=FLpz$HsoT9)Rkd*!SRruhuSK{>)z|C$;Z+$oM`oo_AOH zo(E5B_)0-*-GNh5LIP;ET6pdHb-%oM^ONUJpKkneeEctK0qEX|Jv(+B4OUm-YYjgY zQwqM;(0^J(NeLwcAOx5hjtG_r#uykWV@nf<7Me|A!|-tcKkggAwpw#PID58o`RY}? zd-EndrI7Lc7$_-+k`h9Q*nT2J)FFEmmEeB><{OQ< zHc&bF#1nAGk7J?P#LcNGv{zOjr35<{_W&~(fPat@ju}cRRJLuy-d($JX#akI2tlg_ zBAUG~fIF?087!4RL>MZUarDtgkmVmvuBjCSsgz5%x8^UvqA*+FuyW2+DXLds6aq~nEB05fFQnn;>cBqbti z=f8R3!kxYVjvYHDvRZ!yK-}5Rp;Rcu07*z8Af<%V8d51x(huGDq)&mhmcrH5*Ra8m z>4(*&r3Z!zg#$zcV{N>7Vr80D#|5S0Lw~6!`;G$uf>w)#5Wm<6pyNO(mm6ka3lYIt z3j*R=cV%^#3n@U?dVGnm%gyHBTU!62Z-5|*4hz6{&Vl3l+l*4W<3K8sI3cwLr0mS0 z3u1Y3(OP3Jzj*$<>$?Ow-~TL_1vv+6E#~X>YfJUI>HUF7vXtqm*E5{8n7?&v#eW&| z(njKU0SGBSk)CWp81j2_a~JBjZ~v*iw8UVJZ%PgyCPL~|@0gvMiiqf`(-$uWeFIdh z)r=NmhjR{56rtH_&AmP`agD9L&}uX+5Wo2t05gM_K?y(_NW#lz6@Za`#5({Z3?+uh`>Z3=RnqihyWs_4l#i8$cWNf*J`7qyZZw8 zYhChq?uEiIT6TOIBUVqb>=&e0IGZU4hW@w|MHnL zdP4vq7qhb`CDt*wcC-S18Et8mC!OdS4RM<3ide`C`$_6^rL;XU+_--viA5bVOvGgRvHo zG5GYMLmJ6O+>?2y1jcl}vvYSjls+8;`Meguv+DuqiOI>=k3RhHuO;v~2!SAqu5i1( zv%R$RnD%|e-L+5ccMd{`PJbDQ=)Vpy15t$CV`IG9Y=*nve!KcC@WZ4@f13gR*bUG* zOO6~o_$kL6e*2+^{s91uYV{jR>mTJxrQ*==u(zdJm8EhSem)QFdGS9Y=U~DR!SXU% zjRx*aPn&QuV2|VJNwrD8#h`EjNfCsp947GC0^eU;2uCqFngZXJ~7+! z%uE0PC&$LF0C>DBvBDZ#EG5^v0KRp<`s@w%Ck*iQ|EqWx#I-)ePkkifT@b%p z2jHt8sdyK})q99P^?$L5cR~E7OZ>|pt9Td0r3g5=*7|<{JnFP0r1W5t0000bbVXQn zWMOn=I%9HWVRU5xGB7bSEif}JGci;#Fgh?cIyEvYFfuwYF!;jw!~g&QC3HntbYx+4 zWjbwdWNBu305UK!Gc7PPEi*AxF)%tXHaayjD=;!TFffUqKr(m$000?uMObuGZ)S9N nVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs00000NkvXXu0mjffHPMs diff --git a/files/opencs/raster/creature.png b/files/opencs/raster/creature.png new file mode 100644 index 0000000000000000000000000000000000000000..52c41615adece79dfabeb4ff91ce1a40fc125754 GIT binary patch literal 2506 zcmV;*2{rbKP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000R&Nkl&0tN@bMn&hz>-)QjA$5&w34?I}#)EM6`$x zn>Pty2P^^rdNif4Sj`$K(1uJZmb#y#-Djb(*o;9)er*<8e4K9CNi4z|3TRw=#nP zKQlW5yJ8JU^Yz9ilNLvkjaW$n_)0Is?${u7lluo8Ay^k8N2n*~7m76{0QyISOx$;f z0RE*S3BwI@@o2>yCUXjYy*Li1G9$3fqGKq(SDl5vVh00$GRuNPNugM+_r*?|4u_nf z*q;!Lz3~Q|Otav4iW%FZ{IO6jfR@MZo2ZRXL}>LDOYOdrSKlUE&`*H-2?HZ*itu!8 zDITqwhu(S7=pnVI=fTokCVL9ronc~Vr$8TNP|f5>+a|f^bz3mg|V1zHo$7oVU0a-oc76? zFAdjVmfj!EAR;z!a4r5*{@fIR0B^h56u!%LNf@?5qk(r#t+@W`^#t?@7R*MGff_;%A@PMA< zF~yvwFc9r4db&3*gvp$OUn@<-^2mU3aDz-V1)Qp#);vHYV1f_}g(wQ}VZb+=RM<#Z zD3fsD&vt)0MFW%;laFYK>6`eAE?23yQ( zEYo_!!1Wk*Gy8}}uNTJSd7}$|-&TWHtyLJ^T#4t+OLL-eF~^4ealxon3!z|pjJlEf zkM`!pV0c9?UNo2C`z4upP@RE+$~5#50VY|3uxXhKKYrhfESni7F`<)8wH%U>OUg$9 zp)}o_0}G!8gC`dbqYho$R$^X?1r~of_Bq2yzy@@Z3Hc{t(>sWcCMJ64zF zVBeM%IMvaJ&UF>Ahxwzf(1{R*c%1f4;YxgCRA4R9#~d$r$XV{^-9GyNF*15@lMze( zpW1I*dIXjiCF9YxF63n-;`Gi2{BY+ChHjq3gDYLQd+`8np6SGupk}$hQnJ33GCnZT|1aj*81J7?YIw1u0dIaD z!SJI&M1<;bbjuR-9^FDf+drK5;HNqpakzCE{@hf~fa^6f9B6I8g@c<=J1-G&M94Jr zh5#}0KY&YF?#x^mH=+n1Z>d=#9H}F;A4~{CHd#J;4>V)!rzdzj_8R?tConJDiL8W3 zl+TVuU6B(t1rAh_ske|!y&Ojv;v#~O5<_PH2k`IqHe<#7RG3K_Dr7vwalU|($WKO{;GfQ1b&`JdFRBR6d?A|b=X~?)^fb#XJ9V_wEvjP0`<+E{c zs)N7YIDrR!UAWhC5O>b)#f{S)(}Ex0@kcDmjfF-c{P%Q&=#vsmjLazY9w`YAAk@a< zArai@;{hh~-wVED%>qP)Xke9iLCIy0%xE0j6w-!`wop7=lmdG&F`cg$;r`_#zZ<-B z-C~qvSfTTwd!mZ*3N4rQ`4U9>N(Ot0upTeV#?XceB!=rqJ0{^oM-y(J-Sb)64{WZ( z+NxY6MFt|6*!g;5z0`iI$vmJt!DlrPt&qN;*8F5uK7QP=klBn~+wC7ZK@v|fAEd+(YXt_F=`4_4TtNM!$BI^Xs|~1E?h1` zo=%2V0z46XLzseCujlmpz~lg|zLM?@kp`U3h{AR*Ai}_gTFF|9F3{Avx>-~ub`0|lRJV3*8Klj-Z&(U U?%gBa9RL6T07*qoM6N<$f*UxK2mk;8 literal 0 HcmV?d00001 diff --git a/files/opencs/raster/leveled-creature.png b/files/opencs/raster/leveled-creature.png new file mode 100644 index 0000000000000000000000000000000000000000..4aa2c56cd7bfc3407f8aa7a56830089ccc022461 GIT binary patch literal 2212 zcmV;V2wV4wP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000ORNkl3WL7}&?` z?##~a&OX^)*ar)Xd3ud8VDm5-f(Z~1et>c8`cc1=l1A8x8as-U_*KPmqE@2qk6Lcj z)>VI0RVC+FDc{Bj zJFLw`PV3E5j}ou++Q%#N?BgXaTRfo1qXt1p{W^?q1w3DoueU|>ac*}je*FENxN`hC zynC__7Y}ygU_%-5EYkg;Vs_3&;(sO(b=j^QYO27`UKzrfoy}-3$;UdceX^y<_s>Jk zmAG`I3&*xr!7YoQ{9g!^xRv`qKeG=98p`3bnkRya+{{3fcEN8o-{>v#vGv`lOmA7U0GB*^LD*{Pgs0#C(p)fL^@ow@Qx%B#C0PD2g{|j!Tj>MKkCgMuP!%s|=?sLNW+{Opda^ zD&5>)A4OkP5KhT-aTWnqFDduIsm>a_Hq?d}``&?eotnhalfWs_Q-=_4iI zCQmTh2<-72A&VxVzGcq1EbLhtyYV)v@|C1DP{O~RbI!`v&BBN7kW@l<;}NB6O@@j zCX&KtG16U&58gV0U!FgXa|b$bdRG$~%0p^Y94&)amV{AW6hOe|LD27k-EMyz`E+m= zIuppu%tU&6I*BigcaHSn#qCWP-qnILLoL`-6G7N2PI)BbV2aNwUGFaO;f;OI;KGq^ z75s(njVSgxRS*WRE-S)dPb+p04q)Wy9$X}&Io7usZ5yI!Sr&I1NgmvyVS@WL)ghVgZ1UMKSRKZ98cQ)) z8$q$#s)~ziURx2t)}~Fkefu`HwYTBYu^u&3KcHv^J2qo*U>Ejp??TjTM{aJe3eM3p zfp!A_^j8<~`}ari?)P@!^?e<9iO6@a&4W)A#vd!vZ8l!@%f?T_76Sri0eL3jfhd|D zvB*jz1=!PBi*2oqxNy85Cuo7*&1HDGe={0tH>kwgTU$^U@xY+dV)g3PDtK0A2Hrcp z7r(ju0^U5h4I?`maJ;h`dmGoH$tS~Y)Wzqt;)HrhP@^m=MNtsU_afkR!RxXk-{XM8 zW>M2#AN8ZLt_Gz+KWvf-85tQ^xpF0zELnm)*@R0+yK(+-*9`EkQZGtnEo=te=)8LY zk-1L7nlg~#u*#DKM?DXVNubCzShZ>umM&e2RjH}S&Cb46?2xB=qIuX`U#yn)xpJQx zd7-FpS&&y=pXE-!*I2s4C~d?Zy#v%2NrL1o$XBJNp{1 zLDuWcGaElHkc|k*26#mQPNVK)0)K4DDgibJwouwOU+$?XfzxdI?Q|0K*Of#m*zt&v zYB;&1b`6P+`kfsR(_4^A5l^h)G6@qsWj<{5n4uW;ugx%`0!2Q&w{`uW2b!wlA(!n> z>qB|}8lpX15e=Uuv_OELbL!dgxHVZ5>=E20?0#mmSuKxh#YBu}&PIA#+GPeK0@t>N z?ARJoI0L_)L7>oKefv~@BYyJg9$cpWeyO(}yX%TUFF~)<{e#A5G#)YVlfZdn;xcgu zPzh8qk{%v0m|_&JHh3j$30UDUBoWvj3#V2D-1mli>ha1zGfsBZpnrW3HX^`L@}fNE z1LqR4P+1d9g7vX@@nZE1U^nW=S}FP(r-8*cIwJ#oQ|7ej3vJSseAyT;amj!2$;O8U zZLXS124{Esy0oiX@>k%j0q%qZiG>Rn!eY>$4M}=DQ|v-W)W9KVW3vd%byOlz?VvGE z0{c77UvQn1Yn}|wk*l>Q7v#=ZuwVf^Cf(GQpbfPi5jH_LHt&guA0W{kqPkD9x;YD+ z0Upx@mjL(MWYiQ=f3FQdHhif8Cb4MIA_$pjXp1<|;HLwNpuKAmbdhgL;8vpT=2CkC z+)B>ZK)}5liZR@^5d(Em33e3yHEyS5a3;ldW?iu0 z_`1Mh!N~STygJy7!|m%Jkt1>mSO-Q;&O@u9yZ+SQ1wFXPbkVuSilq^05r~6w;wk^bho(CND z5FI)z+%iOpo;AQ3;CXd=`qY0-fRsPXdpp;giO}`EAaSA%Rt%K%A~s^>gjB$XKW&W}Ir-WVllpn3YedznhbtJ;`3cSy-`R1shTH zNhD_NhTL`uW8tF}?|hsAwpIe0v61k?l$omp%9{9yhLfHfXELfG(U|WeXBGiU{X+(3 zB0Lh;91#(i^eED*9d#30A_S7Yymty>3LEG$y6kVL6W7Wq=h#ygk_46%A m&qe5+4{4pd$=?8Tz55@NYw_ktWMjYp0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv0006ONklS0#WHT=4)>aYX}=;EDwx#T5yFR>drnW$aGCFKv6tu@`48mdEXzWvR028>m`cTodH}}@g#!3} zzR!T)9~Ar6{QD$T0LSzBJXnv8KDhNZli-pnz{dxJ0U(@fwy_*sbO1iy@An~_&4SD6 zd}l(Tb<#Iq{7!HQa6FYtfz4`VH#auc0FK|rTa5ywPaDO)NG! zal7x;#J>aJIQnSVw^$?{Dx^Vm_!r9s!%Vfp=M``sAHP+rRVWsV5DErAxz8t}Lxs2k z;c)l`{ez(>>Vuo@#D@xT0Gg&>EoSrhKk)eyY;SFit}ZWSA1b63_yQjhWTXEyacuwq N002ovPDHLkV1g@2BNYGu literal 0 HcmV?d00001 diff --git a/files/opencs/raster/probe.png b/files/opencs/raster/probe.png new file mode 100644 index 0000000000000000000000000000000000000000..2e4c553279ecff5d4e7cf5d3d91984f06bc7d569 GIT binary patch literal 583 zcmV-N0=WH&P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv0005DNkl{|NlP&t+Aqlf`F%|=Rr4D z*9)#LE-R4jql@J}K0bGj9zFX1>eZ|N7c5xt-`?JS7t9efbpXicFw5`XzYli6;lqdj z7ZnxV1V&V6z+)3Y#}?{+|#Ze-9|HKr;v6v%I6D;RbMt5>i7f8f9Ya6X4+HT2YutF$G%96+|*(ZS)fzrX+6 zwQJY@U%!6+e_|~sI|R@zx3{yiO-f9ZcX4(;VPj)+!P?pyrM$;i*N_|n*es`{G9$?W z)V7?YD4>PqL_2_1mJ{UwT3Sxf0kpOpuLI~|IZg-A%W|v^pr_>+4xqQ?C=M71%TXKv zYO{lCHBiL@D%&Y3UP;jlE{Y=~BD`9fn?a4mpY*gG9s;1?4+#nRTvb^Ka>Nl*d_bvM zcx4nE6jW1MQu4nbKmWhEnHk+2fl?a=1_sW_&dU0qmYVwC#MqcFj=-pny}iBXBqk*M zkBN@{Z)jjZb4Orp54gIz&It_-{pRcA^WVtOa0;dIOje5s7zK6udU~KvqyQ})003gN VHPn4~U(x^o002ovPDHLkV1j(X_g4S_ literal 0 HcmV?d00001 diff --git a/files/opencs/raster/random-item.png b/files/opencs/raster/random-item.png index 349130abe5b47d0258e9abbbfb89acd51da39df8..0b2571422cdf1f9e396129f80a800dabef387d88 100644 GIT binary patch delta 1975 zcmV;o2T1tL49O3W85ITq0047(dh`GQ00DDSM?wIu&K&8HArpTIa7bBm000XT000XT z0n*)m`~Uy|8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900%fpL_t(o zN41yPQOP0{b*IQg36d>zW%J`A=v*d4o(5;o93G|ipx+{ebbOAD>)>D*a&-dC5SIYU4 z$S@5O_5|T%Ni?or%D}9|_t>3*5S=nYAEfwrdmxX2 z|NG-}nBLySyXk-6&164bkf1Jiro+d}b;4fwq5`0A_D~5^lJ~EFfA4w$e*0%VUKtz6 zYb&MOijcrnpL{j!k2-(u?~x(P;H&;4$V9Lg6U3r3;G=QN^3}S$ z)&+=v_fR;0()n>sKA!B4>-}9!S`XoSg@jxGe+hp;F6Buy9-?0|lE1~(?hIVJl!>mE zWTp%kniA2`d;piur6TP>FeGm5u}yl_pX~``!3=Nk{;@o+IF4b9|f z#k0qC7$2#@)BBY$+^fPbw@PudF9$yqML{X!&8*S5MJyD=yaAAg)BAagC(4VWac3YO zlfQq~lCJN?>xm&ukN4x{(>_d&cH#NsHar{o5u?K=@!;C`81BzSbLDPq&?!wyDX(R| zAZ!NkS+z^wt{DFh{T+v4B!=_Kc!A9SFlL?)l9@k86qjQ3P6<(6j7LL7csN+d!0%qo z!|lttxYe73_R|SShz*3R!08G7PFsO|6###6F$qcCSVeI(<8agCO$2-c?_S;|LG;1+ zb0u!{(|P)#M`GkTaqyLupBcJ-T2q55k~pMXftEA)hG7D%S#QZRLa1`VliA@T_F;QAd`QJ zQS@Cj%9a=Yk7`LI?x`tQL#V(U1f){A%kVTt1tM-ZROlDvUySh#Gv3;}t6>r1c>q zHq(3I5CeZdbDx1vkGGSQS1@o|^TdDnzga2w(W;S=5)O^0f`RjRJa9N1Y!CNmlz$2D zX-dMyhD6jC$6&Kw1*t2$+~S1ZUakXmC*#OyRTJ=SChaeNZLosVhV%4PS<+77KV3Xx zskw(*!ob;VHe7@}oA9o>{pdIqkBZz#Xq19C^tND;F>~G)p*4-%JcidVdKiD@w&1ke zJ=~R+n&)M1w`#bQ_zeu)+1VLRPEMAzo0Xg4?NxhlwmcSzF@BJXIkha6oZt21sl9kP zR?jGZW$gM&xp~yCbY$U7^#L?hC0N1x&ZR-6aI?VqJT_BvTky7%yKs&KP(U`P%#Hnk zwa#DqgxV^d^EZ=2bHZ)SdG>#yaO~Nkvw}N1IwEX?W?pzp*-ji!4~0auYJwFS;%*q~ z&ta5Pdo?%QLMBsNw%by3bJ{7K$6bZSvN)#UzD&DWIfXZu#Gp7M6rOUvfkj5oaOYYc z>Hc=c+wE~UI_EVdaaJ`q!>bBo7KAq*k3vz}#?Jw4)T;~wJz0#s(#3zWkaDxhR2Rou zYEI$N5xzKIv(GO0>B4QuPY!`X%rUY8*GQhwTkhGZyISK3GF6A0nYK5S$wSFH-{Ruq1S2O2gnQgD#jY$Xza)+O{47va%TC4WX zTXULrs+_`49gRTB4nKd0c;5`Lq+(9w-W>tBNml5S;WC?BZ8qHOaHU7LVRuv@j%ROK z6udk$6d`^R@YxP2%r06<}KW_GvFR$iSGhP2oK zxbdBs^PLI6T_Mni2CGeN_4}>%`CQ7W$x!8H__Afo5EJHY7d(HL)P9Xx_<^K9&gv?b zt>&a`3HAIyFPR&cvcFoXvlk0ZJ5^5MOP4N1Ug}21;mmVxOL@*d9oA{w;KFsZTuD~< z0LergIiY5blAl+N<#FgFW-`}Sqb5VsPL(eNr!`OA;SVo4-?UojT=3;l^3_GeoMS3s ztxC!p+e~(M@~(fiDE%%1Ww~2$>Ua!ljzyvB`|bE4e=D=qP8^9qX?7S&$PX22ug8eN z6dc@uTyh;BCZCPp>diEqfa5Sll*}$50Sx# zJl<*-gH|mxXjMW3S+52!g}^}FjT($v!hJ}`j65y2z-AZLe*lrQqikNLH*f#|002ov JPDHLkV1g>3&0GKg literal 1612 zcmZ`(X;4#F6uyB3Lc(4G1p{F-vIPT}$j}r42}@WhV^AGn&==Nvijd%jsxGa8f0J_;jomDf%A^dQJ z&d?E(7b3I_rt(nI`NGmZaOvnWSh_0@#m6er7H!v{p_4Tc< zukY*Y16|_;g1xGS8$sZ^>=CW8jNyu7$vZbwH4g+jsO@!sCvDwWE_#Dv4)@cI1J)z$g=c{ew= z#>U2`rl#fPgty-U-tC$6c!fJ>2w~C zx45|Y`0-=tUrS5t;lqbSB5`0~prxf{aBvXXtE#GkibX|5wY9ZNOH1wT?Ik58t*xz= zmX>X8Z9r~rZtm~zhrQ(GB~jmmmw{n11YO6&`4}dn;<-{8h9%Qtz_3XH^{7r9 zCX0i@YDtaT1{p-*o9gRXxuDF3uE02ne z>wgWq!X+FC4n)NS>ku&XGD2dq;FQ%Ty^bU2u&x4OBs9=p=>5A`utv@-II9 zs^HRv9Ytgjm6esH%tI0rp2tZ&f8)}!R(l4cZMW+#B4M#k^#`fsgDwTJQhDS2 zb-$z9bi&trs{71RBn9o+(&Z%sKmGjh6N$qy@K?r;`~LicF+sNJMAFh?DN6J0RK`@r4ck3# zL}zNNgZ(#39%Znr{a$rJLc;XaJG~Ug;r-Q@F0zzM-Q9vHO4aanLa3tZkr&)c&+hI! z4Lr)s%&;S_Aj)$$&53qUbRxF+*?HyE#ZUMn4Nk;Ao$8AN1os3nJjyldIsGUKQ~2at z{F5m`RCIko98SF7p+Z4F|IFMt<=l;w)Oo){rM*M#z4;{knM%^B+*CPfZEcsMd}dcf z1t+OXcuOG>To1cqC}fJ0#c9HprZ;s%JYLqbo~w67ldW74p~l?(NDID9^`(35QNu99 z1)l4nn_8AlYi86s+{o>L@6F4n26om@+%id+rI&9c6DN)zNK*}@jpW!~9F8d7aDNwD zoqIob^{?QSbzJF&zxQhIq(e&Rl}Xiig5OG8UwCWlc%L*4&_*pjEorRR7vOh_c1pP) zN)zLyNj~DtBmm^e^zdRZy%=5|LJy`7lkLOuc4d0{FquahYD)eSkd~e(Nk0Am0gQPX w8v-oV6$I(Y(wz9rB$Shr<1RUonkA0UNODilJa+XJ#|lU&lp7IvGeD&H8)U$05dZ)H diff --git a/files/opencs/raster/repair.png b/files/opencs/raster/repair.png index a8165827790baac034005d1b4729b02ad45e5f70..5e495d8fd72c88a04aab96c5eb72ad11fb5ad9e4 100644 GIT binary patch delta 1256 zcmVN2bPDNB8b~7$DE-^4L^m3s900eJIL_t(o zN9|TePh4jdudlDgjdU{Ik?(UMStE=Sb==i6fpP%HXQb{WMpP%vd@sWJ!@Uz}tUXm9* z&&SilL-L@*@4CCWNp5twhO3K<FFtskB@P9c!-081MKbXVP|ItTU%S$*x10@ z+8S0?R>bp*i;I|_pU3R%ET*TYF*!Mj@$qqtj*en@co>6&gXr(?M^{%Df`Woz@#C{+ z@7LGYMd5$l-Ca?Xi$xIuF3hADaC>_jo12^9XZio-<>hOznVA_(O-%`~v9U3XjEo4N zfq?<^_4T2*w--G zLQ7<>SRPGCh){&DhJWu1o|%~mTN|5qG;lY74J5v5Lk9;3Exq)Chl%h1zTolk@gJ$< zUv7VkdXqUoFZS~+9335r!$ZhZeb+lDaM)N|>&@+%TM4ig6A}_oSy?Hp#n&-0F=2M# zN=r*w_I-2Ucisi0hK@qziv7z<7_4P#+9{kq(1d^YU<9}jrQi2jt@barB-_rU)%1E; zTUl+~1^mtm7>ZGpzU7?YkolU=>+9>0o}PaWit(gJA>gD?T=5`s!hIex3|?DXi?p;f z*xB0VJ~#nNF0D?d`@~nk@*5|d0lcQB2Ib}DpuqX*3+y;M$)P`hq}obhOxdya`uVSH(hNaPHn*=M2snP)19Kmk$pruU#h7 z-rf$bZI*yx4f6^$Wi?ZsGdQcpofi}ofVV7PM^;uAGBPrR8n+UluNwalT0%TbTp&L` zAGx`?$jQzYMR>8W%~DfSk)qQfDJg#miHV7bkBdWWY^>-olGZrOtqlu9XlN)j8V%I1 zULiO*7+jk%Om0K6*(qCzrEY3!LPJ9X>gwtQp{lAX@LJ{h;4X`bimtoNCW1_kEy%uCqb?q4Iv98h+!{f2W13e0umr3fsh19f+T22 z$bk?MWQ9l)2pE>2oGb^`sy%Df7VF8<_D*s1(cbm!AN}6veb@Vb?|sJ;2l$h0*Ep>U7^#B(;v@M+%+D*-d9-X=0IC#}EJUWoYJ_*W*JQ`Zl zpwhO~NaSJ;kDW?S4hZxQ2tJ(4J=JDxl2=LT%v4`r($1Ybsln8$8il^QwawU=LQlqc zWAeG|JZ?^XW38d9!!p=ovgngi60lgTgM$N+Ow3@UilxPMO*MEtrqk4+P@ZmV)~aii z3A8w4uTE!bj!ih`;^Gn=6E2kSHT7pzwF+)=UT8#M#L=*@s9;drDGn)IibzK+RO#n^p#wIYUHbY~p z;X==#VPtIJQcr7VZ=0#F!#rr{8!-=$4UFF!othr&9WwO|cTY`^Pu{++Ij^j)KclKs zsO!#Xv}aZ46w*p@NqLc=l*=v7&E;iD6=HLr(K2M#XqB9zoB}~kp_n6*6_!>A#j?Vp zk^*gW?X`)an|CH|-I*L3wHSJJJYgPRln>@vCKpO8OXO7&ae0wY!t3h4q&inAlJX@A zQAJf5=m?N(LD~m|oJsW$ged-$L%u#fBq9Otjq}1DJg{s1UKA3EL?GaBRL$Q@sT@~q+xk?@cR=0paDO$Ip}{90SEA=@RZwb|}!5J2<6dj)x3kB`~P z;GPy&RS7C3nnHQ0T6k7=3>zTw3d0BaMd7Hv5yTLG&f?|`N_5(rGJ6zlLbabZ8wIl_ z>`1f=c4ygA++O6oblHPlgQ=!c^}4o{Ceo$DXkRJ!eQZ+>1VmRobMjk`JwX3g{T{wCRd>&nOF zKiJwtud|MQbXV*ARejx^mS_`aXvFYET-;+OV)GUHz23y<#uxjtX7635%~{^rh-cPR zcsO}>{WkT;nIv;Mn7MfS8EQ0naTjf}`aXjLBM%5lbN57BDoPr*yX|*Ix$bk>yQi;K z*Vv`)Y;i2OIn~5fA^79la54P90IMH;i~s-t diff --git a/files/opencs/scalable/top-level/.directory b/files/opencs/scalable/top-level/.directory new file mode 100644 index 000000000..464bddbfc --- /dev/null +++ b/files/opencs/scalable/top-level/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,4,3,11,19,41 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/top-level/gmst.svg b/files/opencs/scalable/top-level/gmst.svg new file mode 100644 index 000000000..3b59a44fe --- /dev/null +++ b/files/opencs/scalable/top-level/gmst.svg @@ -0,0 +1,1047 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/top-level/topic-regular.svg b/files/opencs/scalable/top-level/topic-regular.svg new file mode 100644 index 000000000..c972dfa18 --- /dev/null +++ b/files/opencs/scalable/top-level/topic-regular.svg @@ -0,0 +1,1045 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + From 076831c9cc5dc0bf9b9bc864eff82a4715856b7b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 5 Apr 2013 12:48:05 +0200 Subject: [PATCH 129/817] added flag columns to race table --- apps/opencs/model/world/columns.hpp | 34 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 2 ++ 2 files changed, 36 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index dfabaaf2c..ad6916ae2 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -434,6 +434,40 @@ namespace CSMWorld return true; } }; + + template + struct FlagColumn : public Column + { + int mMask; + + FlagColumn (const std::string& name, int mask) + : Column (name, ColumnBase::Display_Boolean), mMask (mask) + {} + + virtual QVariant get (const Record& record) const + { + return (record.get().mData.mFlags & mMask)!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + int flags = record.get().mData.mFlags & ~mMask; + + if (data.toInt()) + flags |= mMask; + + record2.mData.mFlags = flags; + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c596bb162..18ff5aac1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -70,6 +70,8 @@ CSMWorld::Data::Data() mRaces.addColumn (new RecordStateColumn); mRaces.addColumn (new NameColumn); mRaces.addColumn (new DescriptionColumn); + mRaces.addColumn (new FlagColumn ("Playable", 0x1)); + mRaces.addColumn (new FlagColumn ("Beast Race", 0x2)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 35fe828108a2ab9b8f71071e3a9e1ec693e39d78 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 5 Apr 2013 13:46:48 +0200 Subject: [PATCH 130/817] added race table weight/height columns --- apps/opencs/model/world/columns.hpp | 40 ++++++++++++++++++++++++++++- apps/opencs/model/world/data.cpp | 4 +++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index ad6916ae2..f65f212da 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -453,7 +453,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - int flags = record.get().mData.mFlags & ~mMask; + int flags = record2.mData.mFlags & ~mMask; if (data.toInt()) flags |= mMask; @@ -468,6 +468,44 @@ namespace CSMWorld return true; } }; + + template + struct WeightHeightColumn : public Column + { + bool mMale; + bool mWeight; + + WeightHeightColumn (bool male, bool weight) + : Column (male ? (weight ? "Male Weight" : "Male Height") : + (weight ? "Female Weight" : "Female Height"), ColumnBase::Display_Float), + mMale (male), mWeight (weight) + {} + + virtual QVariant get (const Record& record) const + { + const ESM::Race::MaleFemaleF& value = + mWeight ? record.get().mData.mWeight : record.get().mData.mHeight; + + return mMale ? value.mMale : value.mFemale; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + ESM::Race::MaleFemaleF& value = + mWeight ? record2.mData.mWeight : record2.mData.mHeight; + + (mMale ? value.mMale : value.mFemale) = data.toFloat(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 18ff5aac1..fb835b986 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -72,6 +72,10 @@ CSMWorld::Data::Data() mRaces.addColumn (new DescriptionColumn); mRaces.addColumn (new FlagColumn ("Playable", 0x1)); mRaces.addColumn (new FlagColumn ("Beast Race", 0x2)); + mRaces.addColumn (new WeightHeightColumn (true, true)); + mRaces.addColumn (new WeightHeightColumn (true, false)); + mRaces.addColumn (new WeightHeightColumn (false, true)); + mRaces.addColumn (new WeightHeightColumn (false, false)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From dc9f5f93e74567acf0b3975e7328ba702bbd4003 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 05:14:24 -0700 Subject: [PATCH 131/817] Use a helper function to get node properties --- components/nifogre/ogrenifloader.cpp | 155 ++++++++++----------------- 1 file changed, 56 insertions(+), 99 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6d08d4ffc..4b0f9ce3d 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -836,15 +836,44 @@ class NIFMeshLoader : Ogre::ManualResourceLoader abort(); } + static void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop) + { + if(node->parent) + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop); + + const Nif::PropertyList &proplist = node->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + } // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -1044,7 +1073,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool needTangents=false; + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + bool needTangents = false; + + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, @@ -1061,42 +1098,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node) { - // Scan the property list for material information - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop, specprop); + handleNiTriShape(mesh, dynamic_cast(node)); return true; } @@ -1108,7 +1114,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop, specprop)) + if(findTriShape(mesh, children[i].getPtr())) return true; } } @@ -1163,69 +1169,20 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); try { + std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + const Nif::NiTexturingProperty *texprop = NULL; const Nif::NiMaterialProperty *matprop = NULL; const Nif::NiAlphaProperty *alphaprop = NULL; const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; - if(partnode->parent) - { - // FIXME: We should probably search down the whole tree instead of just the parent - const Nif::PropertyList &proplist = partnode->parent->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; + bool needTangents = false; - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - } - const Nif::PropertyList &proplist = partnode->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - - bool needTangents; + getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, @@ -1280,7 +1237,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } const Nif::Node *node = dynamic_cast(nif->getRecord(0)); - findTriShape(mesh, node, NULL, NULL, NULL, NULL, NULL, NULL); + findTriShape(mesh, node); } void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) From 12fada28622c329b1119b6e5b6d0fae10e207eb7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 05:34:59 -0700 Subject: [PATCH 132/817] Don't offset the animation time to 0 --- components/nifogre/ogrenifloader.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 4b0f9ce3d..f663cdf14 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -167,7 +167,7 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { - Ogre::Animation *anim = skel->createAnimation(name, stopTime-startTime); + Ogre::Animation *anim = skel->createAnimation(name, stopTime); for(size_t i = 0;i < ctrls.size();i++) { @@ -246,7 +246,7 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const } Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime-startTime); + kframe = nodetrack->createNodeKeyFrame(curtime); if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) kframe->setRotation(curquat); else @@ -441,16 +441,15 @@ void loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - TextKeyMap::const_iterator insiter = keyiter; + TextKeyMap::const_iterator insiter(keyiter); TextKeyMap groupkeys; do { sep = insiter->second.find(':'); if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first - keyiter->first, - insiter->second.substr(sep+2))); + groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); + groupkeys.insert(std::make_pair(insiter->first, insiter->second)); } while(insiter++ != lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); From bf0ae3ae72bb5f0d291d037b41f326707f65b21c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 06:29:14 -0700 Subject: [PATCH 133/817] Read NiVisData info --- components/nif/data.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index a2c9bb56d..c13495ff8 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -297,13 +297,17 @@ public: float time; char isSet; }; + std::vector mVis; void read(NIFStream *nif) { int count = nif->getInt(); - - /* Skip VisData */ - nif->skip(count*5); + mVis.resize(count); + for(size_t i = 0;i < mVis.size();i++) + { + mVis[i].time = nif->getFloat(); + mVis[i].isSet = nif->getChar(); + } } }; From 48d9885554cdddb7c813035f9d226228f91ac310 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 5 Apr 2013 15:42:05 +0200 Subject: [PATCH 134/817] Started bugfix #691 --- apps/openmw/mwclass/armor.cpp | 87 +++++++++++++++++++++ apps/openmw/mwclass/armor.hpp | 2 + apps/openmw/mwclass/clothing.cpp | 61 +++++++++++++++ apps/openmw/mwclass/clothing.hpp | 2 + apps/openmw/mwclass/weapon.cpp | 66 ++++++++++++++++ apps/openmw/mwclass/weapon.hpp | 2 + apps/openmw/mwmechanics/actors.cpp | 3 +- apps/openmw/mwworld/actionequip.cpp | 104 +------------------------ apps/openmw/mwworld/class.cpp | 5 ++ apps/openmw/mwworld/class.hpp | 3 + apps/openmw/mwworld/inventorystore.cpp | 6 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- 12 files changed, 237 insertions(+), 106 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 320944d3c..496e69545 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,6 +16,8 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/player.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -290,6 +292,91 @@ namespace MWClass ref->mBase = record; } + bool Armor::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) + { + if(*slot == MWWorld::InventoryStore::Slot_Helmet) + { + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + + bool allow = true; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_Head) + { + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); + + allow = false; + break; + } + } + + if(!allow) + break; + } + + if (*slot == MWWorld::InventoryStore::Slot_Boots) + { + bool allow = true; + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) + { + allow = false; + // Only notify the player, not npcs + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); + } + break; + } + } + + if(!allow) + return false; + } + + } + } + return true; + } + boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 65f49abb7..bb07e42b0 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,6 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index abad26767..77a7557bf 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/player.hpp" #include "../mwgui/tooltips.hpp" @@ -237,6 +238,66 @@ namespace MWClass ref->mBase = record; } + bool Clothing::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) + { + if (*slot == MWWorld::InventoryStore::Slot_Boots) + { + bool allow = true; + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) + { + allow = false; + // Only notify the player, not npcs + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); + } + break; + } + } + + if(!allow) + return false; + } + + } + } + return true; + } + boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index c3ef22f11..4978fa228 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,6 +61,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0a527262f..51e813003 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,6 +384,72 @@ namespace MWClass ref->mBase = record; } + bool Weapon::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + // equip the item in the first free slot + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) + { + if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + } + } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + } + } + return true; + } + return false; + } + boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 4774bb50b..922cd165f 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,6 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f60567c6c..89671ee08 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -36,8 +36,7 @@ namespace MWMechanics void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) { if (!paused && ptr.getRefData().getHandle()!="player") - MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip ( - MWWorld::Class::get (ptr).getNpcStats (ptr)); + MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip (ptr); } void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 9a44a9979..c147113fc 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,108 +43,8 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - - // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); - if(race->mData.mFlags & ESM::Race::Beast) - { - if(*slot == MWWorld::InventoryStore::Slot_Helmet) - { - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - - bool allow = true; - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_Head) - { - if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - allow = false; - break; - } - } - - if(!allow) - break; - } - - if (*slot == MWWorld::InventoryStore::Slot_Boots) - { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) - { - allow = false; - // Only notify the player, not npcs - if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { - if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); - } - - else // It's boots - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - } - } - break; - } - } - - if(!allow) - break; - } - - } - - //Disable twohanded when shield equipped, shield when twohanded equipped - if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) - { - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - } - } - } - if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) - { - ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } - } - } + if(!MWWorld::Class::get(getTarget()).canEquip(actor,getTarget())) + break; // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2dfa241b3..ee2072cf0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,6 +259,11 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } + bool Class::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + return true; + } + void Class::adjustPosition(const MWWorld::Ptr& ptr) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index de4741e38..4931da7a8 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,6 +242,9 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. Unequip twohanded item if neccesary + virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index dd518ff6a..7a5ae38d0 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -128,8 +128,9 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return mSlots[slot]; } -void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) +void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) { + const MWMechanics::NpcStats& stats = MWWorld::Class::get(npc).getNpcStats(npc); TSlots slots; initSlots (slots); @@ -183,6 +184,9 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) } } + if(!MWWorld::Class::get (test).canEquip (npc, test)) + continue; + if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { // unstack item pointed to by iterator if required diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index e55eca0ae..cc28a0a0c 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -78,7 +78,7 @@ namespace MWWorld ContainerStoreIterator getSlot (int slot); - void autoEquip (const MWMechanics::NpcStats& stats); + void autoEquip (const MWWorld::Ptr& npc); ///< Auto equip items according to stats and item value. const MWMechanics::MagicEffects& getMagicEffects(); From af2a38db3854ecae1c6cdf056ed80b93146fe036 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 08:27:26 -0700 Subject: [PATCH 135/817] Fix looping anims that dont have "loop start" --- apps/openmw/mwrender/animation.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fd575f918..8dbd8d807 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -307,7 +307,15 @@ void Animation::reset(const std::string &start, const std::string &stop) else { mNextKey = mCurrentKeys->begin(); - mCurrentTime = 0.0f; + while(mNextKey != mCurrentKeys->end() && mNextKey->second != "start") + mNextKey++; + if(mNextKey != mCurrentKeys->end()) + mCurrentTime = mNextKey->first; + else + { + mNextKey = mCurrentKeys->begin(); + mCurrentTime = 0.0f; + } } if(stop.length() > 0) From 75b462b9744f1660af0374bc43c984e796008c24 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Apr 2013 18:23:22 +0200 Subject: [PATCH 136/817] If alpha rejection was forced, we also need to force depth_write and depth_check --- components/nifogre/ogrenifloader.cpp | 1 + files/materials/objects.mat | 2 ++ 2 files changed, 3 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f8eca821f..8f9d69f6e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -771,6 +771,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String { alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ alphaTest = result.second; + depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on } if((alphaFlags&1)) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 8740c82c3..49df4e394 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -14,6 +14,7 @@ material openmw_objects_base is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default depth_write default + depth_check default alpha_rejection default transparent_sorting default @@ -38,6 +39,7 @@ material openmw_objects_base scene_blend $scene_blend alpha_rejection $alpha_rejection depth_write $depth_write + depth_check $depth_check transparent_sorting $transparent_sorting texture_unit diffuseMap From 0631b28646c5cfe12360be1356980db93e3ff050 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 10:13:54 -0700 Subject: [PATCH 137/817] Prepare for supporting controller objects --- apps/openmw/mwrender/animation.cpp | 7 +++++++ apps/openmw/mwrender/animation.hpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/npcanimation.cpp | 1 + components/nifogre/ogrenifloader.hpp | 2 ++ 4 files changed, 30 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8dbd8d807..00196c9d4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -45,6 +45,7 @@ Animation::~Animation() for(size_t i = 0;i < mEntityList.mEntities.size();i++) sceneMgr->destroyEntity(mEntityList.mEntities[i]); } + mEntityList.mControllers.clear(); mEntityList.mParticles.clear(); mEntityList.mEntities.clear(); mEntityList.mSkelBase = NULL; @@ -129,6 +130,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } + + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); + for(size_t i = 0;i < mEntityList.mControllers.size();i++) + mEntityList.mControllers[i].setSource(ctrlval); } @@ -457,6 +462,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } + for(size_t i = 0;i < mEntityList.mControllers.size();i++) + mEntityList.mControllers[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 7caf35169..3e7dee6db 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,6 +16,26 @@ namespace MWRender class Animation { protected: + class AnimationValue : public Ogre::ControllerValue + { + private: + Animation *mAnimation; + + public: + AnimationValue(Animation *anim) : mAnimation(anim) + { } + + virtual Ogre::Real getValue() const + { + return mAnimation->mCurrentTime; + } + + virtual void setValue(Ogre::Real value) + { + mAnimation->mCurrentTime = value; + } + }; + MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f1af6a7d3..b7bcad599 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -367,6 +367,7 @@ void NpcAnimation::removeEntities(NifOgre::EntityList &entities) sceneMgr->destroyParticleSystem(entities.mParticles[i]); for(size_t i = 0;i < entities.mEntities.size();i++) sceneMgr->destroyEntity(entities.mEntities[i]); + entities.mControllers.clear(); entities.mParticles.clear(); entities.mEntities.clear(); entities.mSkelBase = NULL; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index e6672541b..819b4d880 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -45,6 +45,8 @@ struct EntityList { std::vector mParticles; + std::vector > mControllers; + EntityList() : mSkelBase(0) { } }; From aa9df818a52574984406733edb7c916c7183b1c6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 10:38:27 -0700 Subject: [PATCH 138/817] Add support for NiVisController --- components/nifogre/ogrenifloader.cpp | 103 ++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f663cdf14..443b20710 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -62,6 +62,83 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { + +// FIXME: Should not be here. +class VisController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::Bone *mTarget; + + // FIXME: We are not getting all objects here. Skinned meshes get + // attached to the object's root node, and won't be connected via a + // TagPoint. + static void setVisible(Ogre::Node *node, int vis) + { + Ogre::Node::ChildNodeIterator iter = node->getChildIterator(); + while(iter.hasMoreElements()) + { + node = iter.getNext(); + setVisible(node, vis); + + Ogre::TagPoint *tag = dynamic_cast(node); + if(tag != NULL) + { + Ogre::MovableObject *obj = tag->getChildObject(); + if(obj != NULL) + obj->setVisible(vis); + } + } + } + + public: + Value(Ogre::Bone *target) : mTarget(target) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 1.0f; + } + + virtual void setValue(Ogre::Real value) + { + int vis = static_cast(value); + setVisible(mTarget, vis); + } + }; + + class Function : public Ogre::ControllerFunction + { + private: + std::vector mData; + + public: + Function(const Nif::NiVisData *data) + : Ogre::ControllerFunction(false), + mData(data->mVis) + { } + + virtual Ogre::Real calculate(Ogre::Real value) + { + if(mData.size() == 0) + return 1.0f; + + if(mData[0].time >= value) + return mData[0].isSet; + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > value) + return mData[i-1].isSet; + } + return mData.back().isSet; + } + }; +}; + + // Helper class that computes the bounding box and of a mesh class BoundsFinder { @@ -330,7 +407,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; @@ -1129,7 +1207,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); - emitter->setDirection(Ogre::Vector3::UNIT_Z); + emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); + emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, partctrl->velocity+partctrl->velocityRandom); emitter->setEmissionRate(partctrl->emitRate); @@ -1270,6 +1349,26 @@ class NIFMeshLoader : Ogre::ManualResourceLoader e = e->extra; } + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); + + const Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); + if(!target) target = node; + + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(target->name); + Ogre::SharedPtr > srcval; /* Filled in later */ + Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); + Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); + + entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } + if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = static_cast(node); From b1257620d90904571a49fb75ac2a2080051311ff Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 22:58:21 +0200 Subject: [PATCH 139/817] Some cleanup in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index db0a47d84..35fb3a598 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,16 @@ before_script: - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 - - cat CMakeCache.txt before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev + - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrand-dev libfreeimage-dev libpng-dev + - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev + - sudo apt-get install -qq libcg nvidia-cg-dev + - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev + - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: From 07d5d26b4a2f724553feb8ecacc9fe58ed15d9d2 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:02:44 +0200 Subject: [PATCH 140/817] Corrected typo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 35fb3a598..b8ebe6275 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev - - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrand-dev libfreeimage-dev libpng-dev + - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libcg nvidia-cg-dev - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev From d999c0a91c692289b4a3aba805c72ae41e4adf15 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:18:10 +0200 Subject: [PATCH 141/817] Enabled addtional Ubuntu repositories. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b8ebe6275..f383d8272 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ before_script: - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive + - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse partner" - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev From fb4f50ce8f577081bfdc796c9f6cbc998debcec9 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:28:44 +0200 Subject: [PATCH 142/817] Removed 'partner' repository. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f383d8272..61d5fa551 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ before_script: - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse partner" + - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev From a48d60b5e34ed1d6dcfe6396392ec40120bf5412 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:34:23 +0200 Subject: [PATCH 143/817] Changed packet name from nvidia-cg-dev to nvidia-cg-toolkit. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 61d5fa551..c57457249 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ before_install: - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - - sudo apt-get install -qq libcg nvidia-cg-dev + - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev script: "make -j`grep -c processor /proc/cpuinfo`" From 99ff89d668b8d51a3f6b46af35a94bc26ef1d256 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:41:15 +0200 Subject: [PATCH 144/817] Lowered number of used CPUs for compilation. Enabled building of unit tests. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c57457249..ee26fd5c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" @@ -16,7 +16,7 @@ before_install: - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev -script: "make -j`grep -c processor /proc/cpuinfo`" +script: "make -j4" branches: only: - master From 6529919102bde1d126121a5669cbb802949162dc Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:01:44 +0200 Subject: [PATCH 145/817] Enabled building of Gtest libary. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index ee26fd5c1..96ce6d7eb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,6 @@ language: cpp compiler: - - gcc -before_script: - - mkdir build - - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 + - gcc before_install: - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" @@ -15,7 +11,17 @@ before_install: - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev + - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev + - sudo mkdir /usr/src/gtest/build + - cd /usr/src/gtest/build + - sudo cmake .. -DBUILD_SHARED_LIBS=1 + - sudo make -j4 + - sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so + - sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so +before_script: + - mkdir build + - cd build + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 script: "make -j4" branches: only: From 977da3eeb80d09d3eccc0d0f7cd19308e2e71472 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:18:14 +0200 Subject: [PATCH 146/817] Change back directory to the one where OpenMW is downloaded. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 96ce6d7eb..8df94ca48 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: cpp compiler: - gcc before_install: + - pwd - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo apt-add-repository ppa:openmw/deps @@ -19,6 +20,7 @@ before_install: - sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so - sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so before_script: + - cd - - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 From 86457ce488b233141091b04487d1ed5d89ac4338 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:45:04 +0200 Subject: [PATCH 147/817] Enabled running of openmw test suite. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8df94ca48..9ed8b7526 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ language: cpp compiler: - gcc +branches: + only: + - master + - travis_ci_test before_install: - pwd - git submodule update --init --recursive @@ -24,11 +28,10 @@ before_script: - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -script: "make -j4" -branches: - only: - - master - - travis_ci_test +script: + - make -j4 +after_script: + - openmw_test_suite notifications: recipients: - lgromanowski+travis.ci@gmail.com From 05e7cfeb70c80ebb3fcaa0d9f984366e65988a7f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 01:04:41 +0200 Subject: [PATCH 148/817] Corrected path to the openmw test suite. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9ed8b7526..54fff44e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ compiler: branches: only: - master + - next - travis_ci_test before_install: - pwd @@ -31,7 +32,7 @@ before_script: script: - make -j4 after_script: - - openmw_test_suite + - ./openmw_test_suite notifications: recipients: - lgromanowski+travis.ci@gmail.com From 9ac56ce60e2d03761be32a3e83e947cdfc9f1f4e Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 01:24:38 +0200 Subject: [PATCH 149/817] Removed travis_ci_test branch from checked branches list. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 54fff44e2..374b38ce0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ branches: only: - master - next - - travis_ci_test before_install: - pwd - git submodule update --init --recursive From 81615c1ae5ac4055ffbe8c6239ebdf6b8b7fb029 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:18:36 -0700 Subject: [PATCH 150/817] Add a custom GrowFade particle affector --- CMakeLists.txt | 1 + libs/openengine/ogre/particles.cpp | 146 +++++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 17 ++++ libs/openengine/ogre/renderer.cpp | 15 +++ libs/openengine/ogre/renderer.hpp | 2 + 5 files changed, 181 insertions(+) create mode 100644 libs/openengine/ogre/particles.cpp create mode 100644 libs/openengine/ogre/particles.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e1b8e32e5..b6a101790 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/fader.cpp + ${LIBDIR}/openengine/ogre/particles.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp new file mode 100644 index 000000000..3453b7f3d --- /dev/null +++ b/libs/openengine/ogre/particles.cpp @@ -0,0 +1,146 @@ +#include "particles.hpp" + +#include +#include +#include +#include + +class GrowFadeAffector : public Ogre::ParticleAffector +{ +public: + /** Command object for grow_time (see Ogre::ParamCommand).*/ + class CmdGrowTime : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GrowFadeAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getGrowTime()); + } + void doSet(void *target, const Ogre::String &val) + { + GrowFadeAffector *self = static_cast(target); + self->setGrowTime(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for fade_time (see Ogre::ParamCommand).*/ + class CmdFadeTime : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GrowFadeAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getFadeTime()); + } + void doSet(void *target, const Ogre::String &val) + { + GrowFadeAffector *self = static_cast(target); + self->setFadeTime(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Default constructor. */ + GrowFadeAffector(Ogre::ParticleSystem *psys) : ParticleAffector(psys) + { + mGrowTime = 0.0f; + mFadeTime = 0.0f; + + mType = "GrowFade"; + + // Init parameters + if(createParamDictionary("GrowFadeAffector")) + { + Ogre::ParamDictionary *dict = getParamDictionary(); + + Ogre::String grow_title("grow_time"); + Ogre::String fade_title("fade_time"); + Ogre::String grow_descr("Time from begin to reach full size."); + Ogre::String fade_descr("Time from end to shrink."); + + dict->addParameter(Ogre::ParameterDef(grow_title, grow_descr, Ogre::PT_REAL), &msGrowCmd); + dict->addParameter(Ogre::ParameterDef(fade_title, fade_descr, Ogre::PT_REAL), &msFadeCmd); + } + } + + /** See Ogre::ParticleAffector. */ + void _initParticle(Ogre::Particle *particle) + { + const Ogre::Real life_time = particle->totalTimeToLive; + Ogre::Real particle_time = particle->timeToLive; + + Ogre::Real width = mParent->getDefaultWidth(); + Ogre::Real height = mParent->getDefaultHeight(); + if(life_time-particle_time < mGrowTime) + { + Ogre::Real scale = (life_time-particle_time) / mGrowTime; + width *= scale; + height *= scale; + } + if(particle_time < mFadeTime) + { + Ogre::Real scale = particle_time / mFadeTime; + width *= scale; + height *= scale; + } + particle->setDimensions(width, height); + } + + /** See Ogre::ParticleAffector. */ + void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + const Ogre::Real life_time = p->totalTimeToLive; + Ogre::Real particle_time = p->timeToLive; + + Ogre::Real width = mParent->getDefaultWidth(); + Ogre::Real height = mParent->getDefaultHeight(); + if(life_time-particle_time < mGrowTime) + { + Ogre::Real scale = (life_time-particle_time) / mGrowTime; + width *= scale; + height *= scale; + } + if(particle_time < mFadeTime) + { + Ogre::Real scale = particle_time / mFadeTime; + width *= scale; + height *= scale; + } + p->setDimensions(width, height); + } + } + + void setGrowTime(Ogre::Real time) + { + mGrowTime = time; + } + Ogre::Real getGrowTime() const + { return mGrowTime; } + + void setFadeTime(Ogre::Real time) + { + mFadeTime = time; + } + Ogre::Real getFadeTime() const + { return mFadeTime; } + + static CmdGrowTime msGrowCmd; + static CmdFadeTime msFadeCmd; + +protected: + Ogre::Real mGrowTime; + Ogre::Real mFadeTime; +}; +GrowFadeAffector::CmdGrowTime GrowFadeAffector::msGrowCmd; +GrowFadeAffector::CmdFadeTime GrowFadeAffector::msFadeCmd; + +Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleAffector *p = new GrowFadeAffector(psys); + mAffectors.push_back(p); + return p; +} diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp new file mode 100644 index 000000000..d466bb030 --- /dev/null +++ b/libs/openengine/ogre/particles.hpp @@ -0,0 +1,17 @@ +#ifndef OENGINE_OGRE_PARTICLES_H +#define OENGINE_OGRE_PARTICLES_H + +#include + +/** Factory class for GrowFadeAffector. */ +class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory +{ + /** See Ogre::ParticleAffectorFactory */ + Ogre::String getName() const + { return "GrowFade"; } + + /** See Ogre::ParticleAffectorFactory */ + Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); +}; + +#endif /* OENGINE_OGRE_PARTICLES_H */ diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 05760ffa9..c9e91968f 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -1,5 +1,6 @@ #include "renderer.hpp" #include "fader.hpp" +#include "particles.hpp" #include "OgreRoot.h" #include "OgreRenderWindow.h" @@ -8,6 +9,8 @@ #include "OgreTextureManager.h" #include "OgreTexture.h" #include "OgreHardwarePixelBuffer.h" +#include +#include "OgreParticleAffectorFactory.h" #include @@ -24,6 +27,7 @@ using namespace Ogre; using namespace OEngine::Render; + #if defined(__APPLE__) && !defined(__LP64__) CustomRoot::CustomRoot(const Ogre::String& pluginFileName, @@ -106,6 +110,11 @@ void OgreRenderer::loadPlugins() void OgreRenderer::unloadPlugins() { + std::vector::iterator ai; + for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();ai++) + OGRE_DELETE (*ai); + mAffectorFactories.clear(); + #ifdef ENABLE_PLUGIN_GL delete mGLPlugin; mGLPlugin = NULL; @@ -197,6 +206,12 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); + Ogre::ParticleAffectorFactory *affector; + affector = OGRE_NEW GrowFadeAffectorFactory(); + Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); + mAffectorFactories.push_back(affector); + + RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded"); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 251dc9c54..ea46f5ae6 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -40,6 +40,7 @@ namespace Ogre class SceneManager; class Camera; class Viewport; + class ParticleAffectorFactory; } namespace OEngine @@ -94,6 +95,7 @@ namespace OEngine Ogre::D3D9Plugin* mD3D9Plugin; #endif Fader* mFader; + std::vector mAffectorFactories; bool logging; public: From b5017e054309cbd77517d6256fb6ca50b92bf9d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:19:05 -0700 Subject: [PATCH 151/817] Implement NiParticleGrowFade --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 443b20710..4a388bf55 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1220,7 +1221,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(e->recType == Nif::RC_NiParticleGrowFade) { - // TODO: Implement + const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade"); + affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); + affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } else if(e->recType == Nif::RC_NiParticleColorModifier) { From 99b915e652c27bfe1bc0e53e2d5cec9d12796e75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:54:53 -0700 Subject: [PATCH 152/817] Fix some material warnings --- components/nifogre/ogrenifloader.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 54d2c8cf1..215462bac 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -712,7 +712,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, continue; if(texprop->textures[i].texture.empty()) { - warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name+"\n"); + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); continue; } @@ -840,10 +840,14 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); } - for(int i = 1;i < 7;i++) + for(int i = 0;i < 7;i++) { + if(i == Nif::NiTexturingProperty::BaseTexture || + i == Nif::NiTexturingProperty::BumpTexture || + i == Nif::NiTexturingProperty::GlowTexture) + continue; if(!texName[i].empty()) - warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); } if (vertexColour) From 1d934e3112423306ac3ae58ffb30412e88274b24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 04:46:28 -0700 Subject: [PATCH 153/817] Reduce some stdout spam --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e9db6d212..3cd78a933 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -13,7 +13,7 @@ MWMechanics::AiPackage * MWMechanics::AiWander::clone() const bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) { - std::cout << "AiWadner completed.\n"; + // Return completed return true; } diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 8402a5b4c..1ff6fbbf1 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -196,8 +196,6 @@ namespace MWScript MWMechanics::AiWander wanderPackage(range, duration, time, idleList); MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(wanderPackage); - - std::cout << "AiWander" << std::endl; } }; From 41ce5464c9088e8c79a6c91fdbb741cec1e51bb9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 05:00:19 -0700 Subject: [PATCH 154/817] Recognize NiBSAnimationNode as a record type And don't warn about animated nodes without textkeys --- components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 1 + components/nifogre/ogrenifloader.cpp | 11 ++++------- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index bf05e7576..f97c50680 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -209,7 +209,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiNode", &construct , RC_NiNode }, { "AvoidNode", &construct , RC_NiNode }, { "NiBSParticleNode", &construct , RC_NiNode }, - { "NiBSAnimationNode", &construct , RC_NiNode }, + { "NiBSAnimationNode", &construct , RC_NiBSAnimationNode }, { "NiBillboardNode", &construct , RC_NiNode }, { "NiTriShape", &construct , RC_NiTriShape }, { "NiRotatingParticles", &construct , RC_NiRotatingParticles }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 3a3cd9b84..361af3f64 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -59,6 +59,7 @@ enum RecordType RC_NiMaterialColorController, RC_NiBSPArrayController, RC_NiParticleSystemController, + RC_NiBSAnimationNode, RC_NiLight, RC_NiTextureEffect, RC_NiVertWeightsExtraData, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 215462bac..377fa9418 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -464,6 +464,10 @@ void loadResource(Ogre::Resource *resource) return; } + /* Animations without textkeys don't get Ogre::Animation objects. */ + if(!animroot) + return; + std::vector targets; // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file if(ctrls.size() == 0) // No animations? Then we're done. @@ -486,13 +490,6 @@ void loadResource(Ogre::Resource *resource) return; } - if(!animroot) - { - warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ - skel->getName()+", but no text keys."); - return; - } - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); From f764f243d2e42ac5e63a9f44e49deee641a69226 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 06:44:34 -0700 Subject: [PATCH 155/817] Fix the particle quota --- components/nif/data.hpp | 4 +++- components/nifogre/ogrenifloader.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index c13495ff8..0804b53ae 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -165,6 +165,8 @@ public: class NiAutoNormalParticlesData : public ShapeData { public: + int numParticles; + float particleSize; int activeCount; @@ -176,7 +178,7 @@ public: ShapeData::read(nif); // Should always match the number of vertices - nif->getUShort(); + numParticles = nif->getUShort(); particleSize = nif->getFloat(); activeCount = nif->getUShort(); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 377fa9418..cadedbd70 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1274,7 +1274,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->activeCount); + partsys->setParticleQuota(particledata->numParticles); Nif::ControllerPtr ctrl = partnode->controller; while(!ctrl.empty()) From 95730cc127149317583a6051df4eea7b331f3628 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 06:53:08 -0700 Subject: [PATCH 156/817] Create entities and particle systems for hidden objects They're set as (in)visible as appropriate. --- components/nifogre/ogrenifloader.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index cadedbd70..3f20fbab3 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1375,7 +1375,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader ctrl = ctrl->next; } - if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden + if(node->recType == Nif::RC_NiTriShape) { const Nif::NiTriShape *shape = static_cast(node); @@ -1396,10 +1396,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader mesh->setAutoBuildEdgeLists(false); } - entities.mEntities.push_back(sceneMgr->createEntity(mesh)); + Ogre::Entity *entity = sceneMgr->createEntity(mesh); + entity->setVisible(!(flags&0x01)); + + entities.mEntities.push_back(entity); if(entities.mSkelBase) { - Ogre::Entity *entity = entities.mEntities.back(); if(entity->hasSkeleton()) entity->shareSkeletonInstanceWith(entities.mSkelBase); else @@ -1407,12 +1409,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - if((node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x01)) + if(node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) { Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); if(partsys != NULL) + { + partsys->setVisible(!(flags&0x01)); entities.mParticles.push_back(partsys); + } } const Nif::NiNode *ninode = dynamic_cast(node); From e0da2659729727481f7984983dc59551a27b076d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 08:15:12 -0700 Subject: [PATCH 157/817] Use accurate bone lookups for attaching objects NIFs don't requires nodes to have unique names, which means looking up a bone by name may get the wrong one. Instead, use a NifIndex:BoneHandle map to make sure we can get the proper bone from a given Nif::Node. --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3f20fbab3..06296ddee 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -380,7 +380,6 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) return textkeys; } - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { Ogre::Bone *bone; @@ -389,6 +388,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro else bone = skel->createBone(); if(parent) parent->addChild(bone); + mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); @@ -439,6 +439,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro } } +// Lookup to retrieve an Ogre bone handle for a given Nif record index +std::map mNifToOgreHandleMap; typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -569,6 +571,20 @@ static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::stri return skelMgr.create(name, group, true, &sLoaders[name]); } +// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be +// used when the bone name is insufficient as this is a relatively slow lookup +static int lookupOgreBoneHandle(const std::string &nifname, int idx) +{ + LoaderMap::const_iterator loader = sLoaders.find(nifname); + if(loader != sLoaders.end()) + { + std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); + if(entry != loader->second.mNifToOgreHandleMap.end()) + return entry->second; + } + throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); +} + }; NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; @@ -1285,7 +1301,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader createParticleEmitterAffectors(partsys, partctrl); if(!partctrl->emitter.empty() && !partsys->isAttached()) - entitybase->attachObjectToBone(partctrl->emitter->name, partsys); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partctrl->emitter->recIndex); + Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); + entitybase->attachObjectToBone(trgtbone->getName(), partsys); + } } ctrl = ctrl->next; } @@ -1362,10 +1382,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - const Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); - if(!target) target = node; - - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(target->name); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::SharedPtr > srcval; /* Filled in later */ Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); @@ -1405,7 +1423,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(entity->hasSkeleton()) entity->shareSkeletonInstanceWith(entities.mSkelBase); else - entities.mSkelBase->attachObjectToBone(shape->name, entity); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); + entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + } } } From 0fb583e0659847a55d198cc5ecd07594bbc7768d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 17:35:36 +0200 Subject: [PATCH 158/817] added verifier for race record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/racecheck.cpp | 47 +++++++++++++++++++++++++++ apps/opencs/model/tools/racecheck.hpp | 29 +++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/racecheck.cpp create mode 100644 apps/opencs/model/tools/racecheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 07766507f..0cf72b24c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck ) diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp new file mode 100644 index 000000000..50bb08a7c --- /dev/null +++ b/apps/opencs/model/tools/racecheck.cpp @@ -0,0 +1,47 @@ + +#include "racecheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) +: mRaces (races) +{} + +int CSMTools::RaceCheckStage::setup() +{ + return mRaces.getSize(); +} + +void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Race& race = mRaces.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId); + + // test for empty name and description + if (race.mName.empty()) + messages.push_back (id.toString() + "|" + race.mId + " has an empty name"); + + if (race.mDescription.empty()) + messages.push_back (id.toString() + "|" + race.mId + " has an empty description"); + + // test for positive height + if (race.mData.mHeight.mMale<=0) + messages.push_back (id.toString() + "|male " + race.mId + " has non-positive height"); + + if (race.mData.mHeight.mFemale<=0) + messages.push_back (id.toString() + "|female " + race.mId + " has non-positive height"); + + // test for non-negative weight + if (race.mData.mWeight.mMale<0) + messages.push_back (id.toString() + "|male " + race.mId + " has negative weight"); + + if (race.mData.mWeight.mFemale<0) + messages.push_back (id.toString() + "|female " + race.mId + " has negative weight"); + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/racecheck.hpp b/apps/opencs/model/tools/racecheck.hpp new file mode 100644 index 000000000..e3f12599b --- /dev/null +++ b/apps/opencs/model/tools/racecheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_RACECHECK_H +#define CSM_TOOLS_RACECHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that race records are internally consistent + class RaceCheckStage : public Stage + { + const CSMWorld::IdCollection& mRaces; + + public: + + RaceCheckStage (const CSMWorld::IdCollection& races); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index db45de43e..5fb37514f 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -15,6 +15,7 @@ #include "skillcheck.hpp" #include "classcheck.hpp" #include "factioncheck.hpp" +#include "racecheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -60,6 +61,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); + + mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); } return mVerifier; From 59f1d4b0476579146f358b827d4ca060f4b0a76f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 09:44:10 -0700 Subject: [PATCH 159/817] Add support for NiUVController on meshes --- apps/openmw/mwrender/animation.cpp | 5 +- components/nifogre/ogrenifloader.cpp | 120 ++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 00196c9d4..2b980320d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -133,7 +133,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); for(size_t i = 0;i < mEntityList.mControllers.size();i++) - mEntityList.mControllers[i].setSource(ctrlval); + { + if(mEntityList.mControllers[i].getSource().isNull()) + mEntityList.mControllers[i].setSource(ctrlval); + } } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 06296ddee..1e42fed37 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -139,6 +140,105 @@ public: }; }; +class UVController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::MaterialPtr mMaterial; + Nif::FloatKeyList mUTrans; + Nif::FloatKeyList mVTrans; + Nif::FloatKeyList mUScale; + Nif::FloatKeyList mVScale; + + static float lookupValue(float time, const Nif::FloatKeyList &keys) + { + Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); + for(;iter != keys.mKeys.end();iter++) + { + if(iter->mTime > time) + continue; + Nif::FloatKeyList::VecType::const_iterator next(iter+1); + if(next == keys.mKeys.end()) + return iter->mValue; + float a = (time-iter->mTime) / (next->mTime-iter->mTime); + return iter->mValue + ((next->mValue - iter->mValue)*a); + } + return 0.0f; + } + + public: + Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data) + : mMaterial(material) + , mUTrans(data->mKeyList[0]) + , mVTrans(data->mKeyList[1]) + , mUScale(data->mKeyList[2]) + , mVScale(data->mKeyList[3]) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 1.0f; + } + + virtual void setValue(Ogre::Real value) + { + float uTrans = lookupValue(value, mUTrans); + float vTrans = lookupValue(value, mVTrans); + float uScale = lookupValue(value, mUScale); + float vScale = lookupValue(value, mVScale); + if(uScale == 0.0f) uScale = 1.0f; + if(vScale == 0.0f) vScale = 1.0f; + + Ogre::Material::TechniqueIterator techs = mMaterial->getTechniqueIterator(); + while(techs.hasMoreElements()) + { + Ogre::Technique *tech = techs.getNext(); + Ogre::Technique::PassIterator passes = tech->getPassIterator(); + while(passes.hasMoreElements()) + { + Ogre::Pass *pass = passes.getNext(); + Ogre::TextureUnitState *tex = pass->getTextureUnitState(0); + tex->setTextureScroll(uTrans, vTrans); + tex->setTextureScale(uScale, vScale); + } + } + } + }; + + class Function : public Ogre::ControllerFunction + { + private: + float mFrequency; + float mPhase; + float mStartTime; + float mStopTime; + + public: + Function(const Nif::NiUVController *ctrl) + : Ogre::ControllerFunction(false) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } + + virtual Ogre::Real calculate(Ogre::Real value) + { + mDeltaCount += value; + mDeltaCount = std::fmod(mDeltaCount+(value*mFrequency) - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + }; +}; + // Helper class that computes the bounding box and of a mesh class BoundsFinder @@ -409,7 +509,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; @@ -1429,6 +1530,23 @@ class NIFMeshLoader : Ogre::ManualResourceLoader entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } } + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); + + const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); + Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); + + entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } } if(node->recType == Nif::RC_NiAutoNormalParticles || From e50b6b1cfe9f3738909e8857b8f67bb7b282ddd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 09:45:26 -0700 Subject: [PATCH 160/817] Apply texture matrix 0 in the object shader --- files/materials/objects.shader | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index d0e817373..4868cf98d 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -36,6 +36,8 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shUniform(float4x4, textureMatrix0) @shAutoConstant(textureMatrix0, texture_matrix, 0) + #if (VIEWPROJ_FIX) || (SHADOWS) shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) #endif @@ -118,7 +120,7 @@ { shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV.xy = uv0; + UV.xy = shMatrixMult (textureMatrix0, float4(uv0,0,1)).xy; #if SECOND_UV_SET UV.zw = uv1; #endif From ebcb4c66c3adc94217bb912f48789ccde6682668 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 10:17:09 -0700 Subject: [PATCH 161/817] Properly read and use the NIF root record list --- components/nif/niffile.cpp | 18 +++++++++++------- components/nif/niffile.hpp | 14 +++++++++++++- components/nifbullet/bulletnifloader.cpp | 11 +++++------ components/nifogre/ogrenifloader.cpp | 20 ++++++++++---------- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index f97c50680..44eae2953 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -345,14 +345,18 @@ void NIFFile::parse() } } - /* After the data, the nif contains an int N and then a list of N - ints following it. This might be a list of the root nodes in the - tree, but for the moment we ignore it. - */ + size_t rootNum = nif.getUInt(); + roots.resize(rootNum); - // Once parsing is done, do post-processing. - for(size_t i=0; ipost(this); + for(size_t i = 0;i < rootNum;i++) + { + intptr_t idx = nif.getInt(); + roots[i] = ((idx >= 0) ? records.at(idx) : NULL); + } + + // Once parsing is done, do post-processing. + for(size_t i=0; ipost(this); } /// \todo move to the write cpp file diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index ed11bdd7c..6e629772e 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -66,6 +66,9 @@ class NIFFile /// Record list std::vector records; + /// Root list + std::vector roots; + /// Parse the file void parse(); @@ -115,9 +118,18 @@ public: assert(res != NULL); return res; } - /// Number of records size_t numRecords() { return records.size(); } + + /// Get a given root + Record *getRoot(size_t index=0) + { + Record *res = roots.at(index); + assert(res != NULL); + return res; + } + /// Number of roots + size_t numRoots() { return roots.size(); } }; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 08625ee9c..6bd43f6e3 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -91,21 +91,20 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) // likely a sign of incomplete code rather than faulty input. Nif::NIFFile::ptr pnif (Nif::NIFFile::create (resourceName.substr(0, resourceName.length()-7))); Nif::NIFFile & nif = *pnif.get (); - if (nif.numRecords() < 1) + if (nif.numRoots() < 1) { - warn("Found no records in NIF."); + warn("Found no root nodes in NIF."); return; } - // The first record is assumed to be the root node - Nif::Record *r = nif.getRecord(0); + Nif::Record *r = nif.getRoot(0); assert(r != NULL); Nif::Node *node = dynamic_cast(r); if (node == NULL) { - warn("First record in file was not a node, but a " + - r->recName + ". Skipping file."); + warn("First root in file was not a node, but a " + + r->recName + ". Skipping file."); return; } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 1e42fed37..830e85cde 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -553,7 +553,7 @@ void loadResource(Ogre::Resource *resource) OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); - const Nif::Node *node = static_cast(nif->getRecord(0)); + const Nif::Node *node = static_cast(nif->getRoot(0)); std::vector ctrls; Ogre::Bone *animroot = NULL; @@ -1441,7 +1441,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader return; } - const Nif::Node *node = dynamic_cast(nif->getRecord(0)); + const Nif::Node *node = dynamic_cast(nif->getRecord(mShapeIndex)); findTriShape(mesh, node); } @@ -1603,21 +1603,21 @@ public: { Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) + if(nif.numRoots() < 1) { - nif.warn("Found no NIF records in "+name+"."); + nif.warn("Found no root nodes in "+name+"."); return; } // The first record is assumed to be the root node - const Nif::Record *r = nif.getRecord(0); + const Nif::Record *r = nif.getRoot(0); assert(r != NULL); const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); + nif.warn("First root in "+name+" was not a node, but a "+ + r->recName+"."); return; } @@ -1722,14 +1722,14 @@ Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group return skel; Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); - if(nif->numRecords() < 1) + if(nif->numRoots() < 1) { - nif->warn("Found no NIF records in "+name+"."); + nif->warn("Found no root nodes in "+name+"."); return skel; } // The first record is assumed to be the root node - const Nif::Record *r = nif->getRecord(0); + const Nif::Record *r = nif->getRoot(0); assert(r != NULL); const Nif::Node *node = dynamic_cast(r); From 9bc3945f406f3cd252d3a05cf00dc175c7fea17e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 19:20:46 +0200 Subject: [PATCH 162/817] multiple fixes to UniversalId constructor --- apps/opencs/model/world/universalid.cpp | 69 ++++++++++++------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 2e5e6a0a0..5c7547d71 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -55,44 +55,41 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId) { std::string type = universalId.substr (0, index); - if (index==std::string::npos) - { - for (int i=0; sNoArg[i].mName; ++i) - if (type==sNoArg[i].mName) - { - mArgumentType = ArgumentType_None; - mType = sNoArg[i].mType; - mClass = sNoArg[i].mClass; + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mName) + { + mArgumentType = ArgumentType_Id; + mType = sIdArg[i].mType; + mClass = sIdArg[i].mClass; + mId = universalId.substr (index+2); + return; + } + + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mName) + { + mArgumentType = ArgumentType_Index; + mType = sIndexArg[i].mType; + mClass = sIndexArg[i].mClass; + + std::istringstream stream (universalId.substr (index+2)); + + if (stream >> mIndex) return; - } - } - else - { - for (int i=0; sIdArg[i].mName; ++i) - if (type==sIdArg[i].mName) - { - mArgumentType = ArgumentType_Id; - mType = sIdArg[i].mType; - mClass = sIdArg[i].mClass; - mId = universalId.substr (0, index); - return; - } - for (int i=0; sIndexArg[i].mName; ++i) - if (type==sIndexArg[i].mName) - { - mArgumentType = ArgumentType_Index; - mType = sIndexArg[i].mType; - mClass = sIndexArg[i].mClass; - - std::istringstream stream (universalId.substr (0, index)); - - if (stream >> mIndex) - return; - - break; - } - } + break; + } + } + else + { + for (int i=0; sNoArg[i].mName; ++i) + if (universalId==sNoArg[i].mName) + { + mArgumentType = ArgumentType_None; + mType = sNoArg[i].mType; + mClass = sNoArg[i].mClass; + return; + } } throw std::runtime_error ("invalid UniversalId: " + universalId); From 98e7b3fd938edbe334de7bfc36aa2d721f6a3b50 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 19:20:59 +0200 Subject: [PATCH 163/817] check for at least one playable race --- apps/opencs/model/tools/racecheck.cpp | 41 ++++++++++++++++++++------- apps/opencs/model/tools/racecheck.hpp | 5 ++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 50bb08a7c..1e7a4cab4 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -7,16 +7,7 @@ #include "../world/universalid.hpp" -CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) -: mRaces (races) -{} - -int CSMTools::RaceCheckStage::setup() -{ - return mRaces.getSize(); -} - -void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector& messages) { const ESM::Race& race = mRaces.getRecord (stage).get(); @@ -43,5 +34,35 @@ void CSMTools::RaceCheckStage::perform (int stage, std::vector& mes if (race.mData.mWeight.mFemale<0) messages.push_back (id.toString() + "|female " + race.mId + " has negative weight"); + // remember playable flag + if (race.mData.mFlags & 0x1) + mPlayable = true; + /// \todo check data members that can't be edited in the table view +} + +void CSMTools::RaceCheckStage::performFinal (std::vector& messages) +{ + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races); + + if (!mPlayable) + messages.push_back (id.toString() + "|No playable race"); +} + +CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) +: mRaces (races), mPlayable (false) +{} + +int CSMTools::RaceCheckStage::setup() +{ + mPlayable = false; + return mRaces.getSize()+1; +} + +void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +{ + if (stage==mRaces.getSize()) + performFinal (messages); + else + performPerRecord (stage, messages); } \ No newline at end of file diff --git a/apps/opencs/model/tools/racecheck.hpp b/apps/opencs/model/tools/racecheck.hpp index e3f12599b..155f79902 100644 --- a/apps/opencs/model/tools/racecheck.hpp +++ b/apps/opencs/model/tools/racecheck.hpp @@ -13,6 +13,11 @@ namespace CSMTools class RaceCheckStage : public Stage { const CSMWorld::IdCollection& mRaces; + bool mPlayable; + + void performPerRecord (int stage, std::vector& messages); + + void performFinal (std::vector& messages); public: From 1f3df4df0f9ccbdb452ea7e88de4b7f02c417a59 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Apr 2013 19:25:29 +0200 Subject: [PATCH 164/817] Perform a sanity check on count arguments --- apps/openmw/mwscript/miscextensions.cpp | 7 +++++++ apps/openmw/mwscript/transformationextensions.cpp | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index f329e30d9..489f6bd3d 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -399,6 +399,13 @@ namespace MWScript Interpreter::Type_Integer amount = runtime[0].mInteger; runtime.pop(); + if (amount<0) + throw std::runtime_error ("amount must be non-negative"); + + // no-op + if (amount == 0) + return; + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 97dc6d718..49688efb5 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -460,6 +460,13 @@ namespace MWScript Interpreter::Type_Integer direction = runtime[0].mInteger; runtime.pop(); + if (count<0) + throw std::runtime_error ("count must be non-negative"); + + // no-op + if (count == 0) + return; + ESM::Position ipos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition(); Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); @@ -503,6 +510,13 @@ namespace MWScript Interpreter::Type_Integer direction = runtime[0].mInteger; runtime.pop(); + if (count<0) + throw std::runtime_error ("count must be non-negative"); + + // no-op + if (count == 0) + return; + ESM::Position ipos = me.getRefData().getPosition(); Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); From c28399112637417ddf66a9b65ebec4409227d16e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 10:33:07 -0700 Subject: [PATCH 165/817] Remove an unneeded method --- components/nifogre/ogrenifloader.cpp | 30 +++------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 830e85cde..5206ef834 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1070,7 +1070,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) + void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -1295,30 +1295,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node) - { - if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) - { - handleNiTriShape(mesh, dynamic_cast(node)); - return true; - } - - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - if(findTriShape(mesh, children[i].getPtr())) - return true; - } - } - } - return false; - } - typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -1441,8 +1417,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader return; } - const Nif::Node *node = dynamic_cast(nif->getRecord(mShapeIndex)); - findTriShape(mesh, node); + const Nif::Record *record = nif->getRecord(mShapeIndex); + createSubMesh(mesh, dynamic_cast(record)); } void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) From 6b151be3f427ea361e03e9830236642b41721aac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 11:26:51 -0700 Subject: [PATCH 166/817] Create particle systems even when MRK was specified --- components/nifogre/ogrenifloader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 5206ef834..6a7c3c6db 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1444,9 +1444,9 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // affecting the entire subtree of this obj if(sd->string == "MRK") { - // Marker objects. These are only visible in the + // Marker objects. These meshes are only visible in the // editor. - return; + flags |= 0x80000000; } } e = e->extra; @@ -1470,7 +1470,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader ctrl = ctrl->next; } - if(node->recType == Nif::RC_NiTriShape) + if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { const Nif::NiTriShape *shape = static_cast(node); From 8bf569d58ab00c1ef804b802e3bec5bc358032f0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:21:10 +0200 Subject: [PATCH 167/817] added basic sound table --- apps/opencs/model/world/data.cpp | 15 +++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadsoun.cpp | 8 ++++++++ components/esm/loadsoun.hpp | 3 +++ 9 files changed, 49 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fb835b986..b6fb43769 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -77,12 +77,16 @@ CSMWorld::Data::Data() mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); + mSounds.addColumn (new StringIdColumn); + mSounds.addColumn (new RecordStateColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); + addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); } CSMWorld::Data::~Data() @@ -151,6 +155,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getRaces() return mRaces; } +const CSMWorld::IdCollection& CSMWorld::Data::getSounds() const +{ + return mSounds; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSounds() +{ + return mSounds; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -191,6 +205,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_CLAS: mClasses.load (reader, base); break; case ESM::REC_FACT: mFactions.load (reader, base); break; case ESM::REC_RACE: mRaces.load (reader, base); break; + case ESM::REC_SOUN: mSounds.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 6b729728f..320480e63 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -28,6 +29,7 @@ namespace CSMWorld IdCollection mClasses; IdCollection mFactions; IdCollection mRaces; + IdCollection mSounds; std::vector mModels; std::map mModelIndex; @@ -68,6 +70,10 @@ namespace CSMWorld IdCollection& getRaces(); + const IdCollection& getSounds() const; + + IdCollection& getSounds(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 5c7547d71..7bdc15c8c 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -23,6 +23,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -35,6 +36,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 2213e15f3..a21d67fcd 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -45,7 +45,9 @@ namespace CSMWorld Type_Factions, Type_Faction, Type_Races, - Type_Race + Type_Race, + Type_Sounds, + Type_Sound }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index e12929cf2..611690ca6 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -105,6 +105,10 @@ void CSVDoc::View::setupWorldMenu() QAction *races = new QAction (tr ("Races"), this); connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView())); world->addAction (races); + + QAction *sounds = new QAction (tr ("Sounds"), this); + connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); + world->addAction (sounds); } void CSVDoc::View::setupUi() @@ -280,6 +284,11 @@ void CSVDoc::View::addRacesSubView() addSubView (CSMWorld::UniversalId::Type_Races); } +void CSVDoc::View::addSoundsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Sounds); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 4132d73b2..e8e716b70 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -123,6 +123,8 @@ namespace CSVDoc void addFactionsSubView(); void addRacesSubView(); + + void addSoundsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index d5ba27377..3ba950f87 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -20,6 +20,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Classes, CSMWorld::UniversalId::Type_Factions, CSMWorld::UniversalId::Type_Races, + CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 87a08d2d3..75d4bc8de 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -23,4 +23,12 @@ void Sound::save(ESMWriter &esm) esm.writeHNT("DATA", mData, 3); } + void Sound::blank() + { + mSound.clear(); + + mData.mVolume = 128; + mData.mMinRange = 0; + mData.mMaxRange = 256; + } } diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 8f59f690a..f8e38ac09 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -21,6 +21,9 @@ struct Sound void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From ca289a317c579c44b83132cf2bb5b471a8d5b979 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 12:26:58 -0700 Subject: [PATCH 168/817] Separate the UVController function out and make it generic Also fix a timing bug in it. --- components/nifogre/ogrenifloader.cpp | 60 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6a7c3c6db..dfdec0bfa 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -66,6 +66,36 @@ namespace NifOgre { // FIXME: Should not be here. +class DefaultFunction : public Ogre::ControllerFunction +{ +private: + float mFrequency; + float mPhase; + float mStartTime; + float mStopTime; + +public: + DefaultFunction(const Nif::Controller *ctrl) + : Ogre::ControllerFunction(false) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } + + virtual Ogre::Real calculate(Ogre::Real value) + { + mDeltaCount += value*mFrequency; + mDeltaCount = std::fmod(mDeltaCount - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } +}; + class VisController { public: @@ -208,35 +238,7 @@ public: } }; - class Function : public Ogre::ControllerFunction - { - private: - float mFrequency; - float mPhase; - float mStartTime; - float mStopTime; - - public: - Function(const Nif::NiUVController *ctrl) - : Ogre::ControllerFunction(false) - , mFrequency(ctrl->frequency) - , mPhase(ctrl->phase) - , mStartTime(ctrl->timeStart) - , mStopTime(ctrl->timeStop) - { - mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); - } - - virtual Ogre::Real calculate(Ogre::Real value) - { - mDeltaCount += value; - mDeltaCount = std::fmod(mDeltaCount+(value*mFrequency) - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; - } - }; + typedef DefaultFunction Function; }; From dd5940b395a5439aa08cd080a0afb3f585fd99ae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:40:03 +0200 Subject: [PATCH 169/817] added sound parameter columns to sonud table --- apps/opencs/model/world/columns.hpp | 60 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++ 2 files changed, 63 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index f65f212da..0416287ba 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -506,6 +506,66 @@ namespace CSMWorld return true; } }; + + template + struct SoundParamColumn : public Column + { + enum Type + { + Type_Volume, + Type_MinRange, + Type_MaxRange + }; + + Type mType; + + SoundParamColumn (Type type) + : Column ( + type==Type_Volume ? "Volume" : (type==Type_MinRange ? "Min Range" : "Max Range"), + ColumnBase::Display_Integer), + mType (type) + {} + + virtual QVariant get (const Record& record) const + { + int value = 0; + + switch (mType) + { + case Type_Volume: value = record.get().mData.mVolume; break; + case Type_MinRange: value = record.get().mData.mMinRange; break; + case Type_MaxRange: value = record.get().mData.mMaxRange; break; + } + + return value; + } + + virtual void set (Record& record, const QVariant& data) + { + int value = data.toInt(); + + if (value<0) + value = 0; + else if (value>255) + value = 255; + + ESXRecordT record2 = record.get(); + + switch (mType) + { + case Type_Volume: record2.mData.mVolume = static_cast (value); break; + case Type_MinRange: record2.mData.mMinRange = static_cast (value); break; + case Type_MaxRange: record2.mData.mMaxRange = static_cast (value); break; + } + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b6fb43769..afa70cdc1 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -79,6 +79,9 @@ CSMWorld::Data::Data() mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 63cbf7ddeb3a00d89dc43850219bfa7e86dcbd6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 12:41:40 -0700 Subject: [PATCH 170/817] Specify a default return for failed lookups --- components/nifogre/ogrenifloader.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index dfdec0bfa..d89d0d30a 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -182,7 +182,7 @@ public: Nif::FloatKeyList mUScale; Nif::FloatKeyList mVScale; - static float lookupValue(float time, const Nif::FloatKeyList &keys) + static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) { Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); for(;iter != keys.mKeys.end();iter++) @@ -195,7 +195,7 @@ public: float a = (time-iter->mTime) / (next->mTime-iter->mTime); return iter->mValue + ((next->mValue - iter->mValue)*a); } - return 0.0f; + return def; } public: @@ -215,12 +215,10 @@ public: virtual void setValue(Ogre::Real value) { - float uTrans = lookupValue(value, mUTrans); - float vTrans = lookupValue(value, mVTrans); - float uScale = lookupValue(value, mUScale); - float vScale = lookupValue(value, mVScale); - if(uScale == 0.0f) uScale = 1.0f; - if(vScale == 0.0f) vScale = 1.0f; + float uTrans = lookupValue(mUTrans, value, 0.0f); + float vTrans = lookupValue(mVTrans, value, 0.0f); + float uScale = lookupValue(mUScale, value, 1.0f); + float vScale = lookupValue(mVScale, value, 1.0f); Ogre::Material::TechniqueIterator techs = mMaterial->getTechniqueIterator(); while(techs.hasMoreElements()) From 50b58b2ead2ae4b4db3ad9936f9a781592f55823 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:43:05 +0200 Subject: [PATCH 171/817] added sound file column to sound table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 0416287ba..75dfe15c2 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -566,6 +566,31 @@ namespace CSMWorld return true; } }; + + template + struct SoundFileColumn : public Column + { + SoundFileColumn() : Column ("Sound File", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mSound.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mSound = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index afa70cdc1..69109bd74 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -82,6 +82,7 @@ CSMWorld::Data::Data() mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); + mSounds.addColumn (new SoundFileColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From e2c6458adb3509388c178f421d08b73787119619 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:48:52 +0200 Subject: [PATCH 172/817] added verifier for sound records --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/soundcheck.cpp | 29 ++++++++++++++++++++++++++ apps/opencs/model/tools/soundcheck.hpp | 29 ++++++++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/soundcheck.cpp create mode 100644 apps/opencs/model/tools/soundcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0cf72b24c..ffd4c7f1e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck racecheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck ) diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp new file mode 100644 index 000000000..52834e659 --- /dev/null +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -0,0 +1,29 @@ + +#include "soundcheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection& sounds) +: mSounds (sounds) +{} + +int CSMTools::SoundCheckStage::setup() +{ + return mSounds.getSize(); +} + +void CSMTools::SoundCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Sound& sound = mSounds.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId); + + if (sound.mData.mMinRange>sound.mData.mMaxRange) + messages.push_back (id.toString() + "|Maximum range larger than minimum range"); + + /// \todo check, if the sound file exists +} \ No newline at end of file diff --git a/apps/opencs/model/tools/soundcheck.hpp b/apps/opencs/model/tools/soundcheck.hpp new file mode 100644 index 000000000..a309763a1 --- /dev/null +++ b/apps/opencs/model/tools/soundcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SOUNDCHECK_H +#define CSM_TOOLS_SOUNDCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that sound records are internally consistent + class SoundCheckStage : public Stage + { + const CSMWorld::IdCollection& mSounds; + + public: + + SoundCheckStage (const CSMWorld::IdCollection& sounds); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 5fb37514f..4003bc884 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -16,6 +16,7 @@ #include "classcheck.hpp" #include "factioncheck.hpp" #include "racecheck.hpp" +#include "soundcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -63,6 +64,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); + + mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); } return mVerifier; From ec7a8f1add42914684290b4e99bbc8d8f054d586 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:58:28 +0200 Subject: [PATCH 173/817] small fix --- components/esm/loadsoun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 75d4bc8de..07af2b5e9 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -29,6 +29,6 @@ void Sound::save(ESMWriter &esm) mData.mVolume = 128; mData.mMinRange = 0; - mData.mMaxRange = 256; + mData.mMaxRange = 255; } } From 4daaa4030d7434b50a2f835f44329a217e9be357 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 00:12:04 +0200 Subject: [PATCH 174/817] Added shader based MyGUI render manager to allow using Ogre's next generation render systems. --- files/CMakeLists.txt | 3 + files/materials/mygui.mat | 25 ++ files/materials/mygui.shader | 45 +++ files/materials/mygui.shaderset | 15 + libs/openengine/gui/manager.cpp | 537 +++++++++++++++++++++++++++++++- libs/openengine/gui/manager.hpp | 4 +- 6 files changed, 625 insertions(+), 4 deletions(-) create mode 100644 files/materials/mygui.mat create mode 100644 files/materials/mygui.shader create mode 100644 files/materials/mygui.shaderset diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9e65b516b..9b2325744 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -44,6 +44,9 @@ set(MATERIAL_FILES watersim_common.h watersim.mat watersim.shaderset + mygui.mat + mygui.shader + mygui.shaderset ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/mygui.mat b/files/materials/mygui.mat new file mode 100644 index 000000000..78cba3f89 --- /dev/null +++ b/files/materials/mygui.mat @@ -0,0 +1,25 @@ +material MyGUI/NoTexture +{ + pass + { + vertex_program mygui_vertex + fragment_program mygui_fragment + shader_properties + { + has_texture false + } + } +} + +material MyGUI/OneTexture +{ + pass + { + vertex_program mygui_vertex + fragment_program mygui_fragment + shader_properties + { + has_texture true + } + } +} diff --git a/files/materials/mygui.shader b/files/materials/mygui.shader new file mode 100644 index 000000000..014558d97 --- /dev/null +++ b/files/materials/mygui.shader @@ -0,0 +1,45 @@ +#include "core.h" + +#define TEXTURE @shPropertyBool(has_texture) + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM +#if TEXTURE + shVertexInput(float2, uv0) + shOutput(float2, UV) +#endif + shColourInput(float4) + shOutput(float4, colourPassthrough) + + SH_START_PROGRAM + { + shOutputPosition = float4(shInputPosition.xyz, 1.f); +#if TEXTURE + UV.xy = uv0; +#endif + colourPassthrough = colour; + } + +#else + + + SH_BEGIN_PROGRAM + +#if TEXTURE + shSampler2D(diffuseMap) + shInput(float2, UV) +#endif + + shInput(float4, colourPassthrough) + + SH_START_PROGRAM + { +#if TEXTURE + shOutputColour(0) = shSample(diffuseMap, UV.xy) * colourPassthrough; +#else + shOutputColour(0) = colourPassthrough; +#endif + } + +#endif diff --git a/files/materials/mygui.shaderset b/files/materials/mygui.shaderset new file mode 100644 index 000000000..980cd4caf --- /dev/null +++ b/files/materials/mygui.shaderset @@ -0,0 +1,15 @@ +shader_set mygui_vertex +{ + source mygui.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_3_0 vs_2_0 +} + +shader_set mygui_fragment +{ + source mygui.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index c9b561400..f9117586f 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -2,11 +2,18 @@ #include #include +#include #include +#include +#include + using namespace OEngine::GUI; +namespace MyGUI +{ + /* * As of MyGUI 3.2.0, MyGUI::OgreDataManager::isDataExist is unnecessarily complex * this override fixes the resulting performance issue. @@ -20,6 +27,532 @@ public: } }; + +/* + * As of MyGUI 3.2.0, rendering with shaders is not supported. + * We definitely need this though to run in GL3 core / DX11 at all. + * To make matters worse, subclassing OgreRenderManager doesn't seem to be possible here. :/ + */ +class ShaderBasedRenderManager : public RenderManager, + public IRenderTarget, + public Ogre::WindowEventListener, + public Ogre::RenderQueueListener, + public Ogre::RenderSystem::Listener +{ + // флаг для обновления всех и вся + bool mUpdate; + + IntSize mViewSize; + + Ogre::SceneManager* mSceneManager; + + VertexColourType mVertexFormat; + + // окно, на которое мы подписываемся для изменения размеров + Ogre::RenderWindow* mWindow; + + // вьюпорт, с которым работает система + unsigned short mActiveViewport; + + Ogre::RenderSystem* mRenderSystem; + Ogre::TextureUnitState::UVWAddressingMode mTextureAddressMode; + Ogre::LayerBlendModeEx mColorBlendMode, mAlphaBlendMode; + + RenderTargetInfo mInfo; + + typedef std::map MapTexture; + MapTexture mTextures; + + bool mIsInitialise; + bool mManualRender; + size_t mCountBatch; + + // ADDED + Ogre::GpuProgram* mVertexProgramNoTexture; + Ogre::GpuProgram* mVertexProgramOneTexture; + Ogre::GpuProgram* mFragmentProgramNoTexture; + Ogre::GpuProgram* mFragmentProgramOneTexture; + +public: + ShaderBasedRenderManager& getInstance() + { + return *getInstancePtr(); + } + ShaderBasedRenderManager* getInstancePtr() + { + return static_cast(RenderManager::getInstancePtr()); + } + + ShaderBasedRenderManager() : + mUpdate(false), + mSceneManager(nullptr), + mWindow(nullptr), + mActiveViewport(0), + mRenderSystem(nullptr), + mIsInitialise(false), + mManualRender(false), + mCountBatch(0) + { + } + + void initialise(Ogre::RenderWindow* _window, Ogre::SceneManager* _scene) + { + MYGUI_PLATFORM_ASSERT(!mIsInitialise, getClassTypeName() << " initialised twice"); + MYGUI_PLATFORM_LOG(Info, "* Initialise: " << getClassTypeName()); + + mColorBlendMode.blendType = Ogre::LBT_COLOUR; + mColorBlendMode.source1 = Ogre::LBS_TEXTURE; + mColorBlendMode.source2 = Ogre::LBS_DIFFUSE; + mColorBlendMode.operation = Ogre::LBX_MODULATE; + + mAlphaBlendMode.blendType = Ogre::LBT_ALPHA; + mAlphaBlendMode.source1 = Ogre::LBS_TEXTURE; + mAlphaBlendMode.source2 = Ogre::LBS_DIFFUSE; + mAlphaBlendMode.operation = Ogre::LBX_MODULATE; + + mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; + mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP; + mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP; + + mSceneManager = nullptr; + mWindow = nullptr; + mUpdate = false; + mRenderSystem = nullptr; + mActiveViewport = 0; + + Ogre::Root* root = Ogre::Root::getSingletonPtr(); + if (root != nullptr) + setRenderSystem(root->getRenderSystem()); + setRenderWindow(_window); + setSceneManager(_scene); + + // ADDED + sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); + mVertexProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getVertexProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); + mVertexProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getVertexProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); + mFragmentProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getFragmentProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); + mFragmentProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getFragmentProgram()->_getBindingDelegate(); + + + + MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully initialized"); + mIsInitialise = true; + } + + void shutdown() + { + MYGUI_PLATFORM_ASSERT(mIsInitialise, getClassTypeName() << " is not initialised"); + MYGUI_PLATFORM_LOG(Info, "* Shutdown: " << getClassTypeName()); + + destroyAllResources(); + + setSceneManager(nullptr); + setRenderWindow(nullptr); + setRenderSystem(nullptr); + + MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully shutdown"); + mIsInitialise = false; + } + + void setRenderSystem(Ogre::RenderSystem* _render) + { + // отписываемся + if (mRenderSystem != nullptr) + { + mRenderSystem->removeListener(this); + mRenderSystem = nullptr; + } + + mRenderSystem = _render; + + // подписываемся на рендер евент + if (mRenderSystem != nullptr) + { + mRenderSystem->addListener(this); + + // формат цвета в вершинах + Ogre::VertexElementType vertex_type = mRenderSystem->getColourVertexElementType(); + if (vertex_type == Ogre::VET_COLOUR_ARGB) + mVertexFormat = VertexColourType::ColourARGB; + else if (vertex_type == Ogre::VET_COLOUR_ABGR) + mVertexFormat = VertexColourType::ColourABGR; + + updateRenderInfo(); + } + } + + Ogre::RenderSystem* getRenderSystem() + { + return mRenderSystem; + } + + void setRenderWindow(Ogre::RenderWindow* _window) + { + // отписываемся + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); + mWindow = nullptr; + } + + mWindow = _window; + + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); + windowResized(mWindow); + } + } + + void setSceneManager(Ogre::SceneManager* _scene) + { + if (nullptr != mSceneManager) + { + mSceneManager->removeRenderQueueListener(this); + mSceneManager = nullptr; + } + + mSceneManager = _scene; + + if (nullptr != mSceneManager) + { + mSceneManager->addRenderQueueListener(this); + } + } + + void setActiveViewport(unsigned short _num) + { + mActiveViewport = _num; + + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); + + // рассылка обновлений + windowResized(mWindow); + } + } + + void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation) + { + Gui* gui = Gui::getInstancePtr(); + if (gui == nullptr) + return; + + if (Ogre::RENDER_QUEUE_OVERLAY != queueGroupId) + return; + + Ogre::Viewport* viewport = mSceneManager->getCurrentViewport(); + if (nullptr == viewport + || !viewport->getOverlaysEnabled()) + return; + + if (mWindow->getNumViewports() <= mActiveViewport + || viewport != mWindow->getViewport(mActiveViewport)) + return; + + mCountBatch = 0; + + static Timer timer; + static unsigned long last_time = timer.getMilliseconds(); + unsigned long now_time = timer.getMilliseconds(); + unsigned long time = now_time - last_time; + + onFrameEvent((float)((double)(time) / (double)1000)); + + last_time = now_time; + + //begin(); + setManualRender(true); + onRenderToTarget(this, mUpdate); + //end(); + + // сбрасываем флаг + mUpdate = false; + } + + void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation) + { + } + + void eventOccurred(const Ogre::String& eventName, const Ogre::NameValuePairList* parameters) + { + if (eventName == "DeviceLost") + { + } + else if (eventName == "DeviceRestored") + { + // обновить всех + mUpdate = true; + } + } + + IVertexBuffer* createVertexBuffer() + { + return new OgreVertexBuffer(); + } + + void destroyVertexBuffer(IVertexBuffer* _buffer) + { + delete _buffer; + } + + // для оповещений об изменении окна рендера + void windowResized(Ogre::RenderWindow* _window) + { + if (_window->getNumViewports() > mActiveViewport) + { + Ogre::Viewport* port = _window->getViewport(mActiveViewport); +#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 + Ogre::OrientationMode orient = port->getOrientationMode(); + if (orient == Ogre::OR_DEGREE_90 || orient == Ogre::OR_DEGREE_270) + mViewSize.set(port->getActualHeight(), port->getActualWidth()); + else + mViewSize.set(port->getActualWidth(), port->getActualHeight()); +#else + mViewSize.set(port->getActualWidth(), port->getActualHeight()); +#endif + + // обновить всех + mUpdate = true; + + updateRenderInfo(); + + onResizeView(mViewSize); + } + } + + void updateRenderInfo() + { + if (mRenderSystem != nullptr) + { + mInfo.maximumDepth = mRenderSystem->getMaximumDepthInputValue(); + mInfo.hOffset = mRenderSystem->getHorizontalTexelOffset() / float(mViewSize.width); + mInfo.vOffset = mRenderSystem->getVerticalTexelOffset() / float(mViewSize.height); + mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); + mInfo.pixScaleX = 1.0f / float(mViewSize.width); + mInfo.pixScaleY = 1.0f / float(mViewSize.height); + } + } + + void doRender(IVertexBuffer* _buffer, ITexture* _texture, size_t _count) + { + if (getManualRender()) + { + begin(); + setManualRender(false); + } + + // ADDED + + if (_texture) + { + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramOneTexture); + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramOneTexture); + } + else + { + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramNoTexture); + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramNoTexture); + } + + if (_texture) + { + OgreTexture* texture = static_cast(_texture); + Ogre::TexturePtr texture_ptr = texture->getOgreTexture(); + if (!texture_ptr.isNull()) + { + mRenderSystem->_setTexture(0, true, texture_ptr); + mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); + } + } + + OgreVertexBuffer* buffer = static_cast(_buffer); + Ogre::RenderOperation* operation = buffer->getRenderOperation(); + operation->vertexData->vertexCount = _count; + + mRenderSystem->_render(*operation); + + ++ mCountBatch; + } + + void begin() + { + // set-up matrices + mRenderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY); + mRenderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY); + +#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 + Ogre::OrientationMode orient = mWindow->getViewport(mActiveViewport)->getOrientationMode(); + mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY * Ogre::Quaternion(Ogre::Degree(orient * 90.f), Ogre::Vector3::UNIT_Z)); +#else + mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY); +#endif + + // initialise render settings + mRenderSystem->setLightingEnabled(false); + mRenderSystem->_setDepthBufferParams(false, false); + mRenderSystem->_setDepthBias(0, 0); + mRenderSystem->_setCullingMode(Ogre::CULL_NONE); + mRenderSystem->_setFog(Ogre::FOG_NONE); + mRenderSystem->_setColourBufferWriteEnabled(true, true, true, true); + mRenderSystem->unbindGpuProgram(Ogre::GPT_FRAGMENT_PROGRAM); + mRenderSystem->unbindGpuProgram(Ogre::GPT_VERTEX_PROGRAM); + mRenderSystem->setShadingType(Ogre::SO_GOURAUD); + + // initialise texture settings + mRenderSystem->_setTextureCoordCalculation(0, Ogre::TEXCALC_NONE); + mRenderSystem->_setTextureCoordSet(0, 0); + mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); + mRenderSystem->_setTextureAddressingMode(0, mTextureAddressMode); + mRenderSystem->_setTextureMatrix(0, Ogre::Matrix4::IDENTITY); +#if OGRE_VERSION < MYGUI_DEFINE_VERSION(1, 6, 0) + mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0); +#else + mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0, false); +#endif + mRenderSystem->_setTextureBlendMode(0, mColorBlendMode); + mRenderSystem->_setTextureBlendMode(0, mAlphaBlendMode); + mRenderSystem->_disableTextureUnitsFrom(1); + + // enable alpha blending + mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); + + // always use wireframe + // TODO: add option to enable wireframe mode in platform + mRenderSystem->_setPolygonMode(Ogre::PM_SOLID); + } + + void end() + { + } + + ITexture* createTexture(const std::string& _name) + { + MapTexture::const_iterator item = mTextures.find(_name); + MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '" << _name << "' already exist"); + + OgreTexture* texture = new OgreTexture(_name, OgreDataManager::getInstance().getGroup()); + mTextures[_name] = texture; + return texture; + } + + void destroyTexture(ITexture* _texture) + { + if (_texture == nullptr) return; + + MapTexture::iterator item = mTextures.find(_texture->getName()); + MYGUI_PLATFORM_ASSERT(item != mTextures.end(), "Texture '" << _texture->getName() << "' not found"); + + mTextures.erase(item); + delete _texture; + } + + ITexture* getTexture(const std::string& _name) + { + MapTexture::const_iterator item = mTextures.find(_name); + if (item == mTextures.end()) + { + Ogre::TexturePtr texture = (Ogre::TexturePtr)Ogre::TextureManager::getSingleton().getByName(_name); + if (!texture.isNull()) + { + ITexture* result = createTexture(_name); + static_cast(result)->setOgreTexture(texture); + return result; + } + return nullptr; + } + return item->second; + } + + bool isFormatSupported(PixelFormat _format, TextureUsage _usage) + { + return Ogre::TextureManager::getSingleton().isFormatSupported( + Ogre::TEX_TYPE_2D, + OgreTexture::convertFormat(_format), + OgreTexture::convertUsage(_usage)); + } + + void destroyAllResources() + { + for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) + { + delete item->second; + } + mTextures.clear(); + } + +#if MYGUI_DEBUG_MODE == 1 + bool checkTexture(ITexture* _texture) + { + for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) + { + if (item->second == _texture) + return true; + } + return false; + } +#endif + + const IntSize& getViewSize() const + { + return mViewSize; + } + + VertexColourType getVertexFormat() + { + return mVertexFormat; + } + + const RenderTargetInfo& getInfo() + { + return mInfo; + } + + size_t getActiveViewport() + { + return mActiveViewport; + } + + Ogre::RenderWindow* getRenderWindow() + { + return mWindow; + } + + bool getManualRender() + { + return mManualRender; + } + + void setManualRender(bool _value) + { + mManualRender = _value; + } + + size_t getBatchCount() const + { + return mCountBatch; + } +}; + +} + + void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir) { assert(wnd); @@ -41,8 +574,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new OgreRenderManager(); - mDataManager = new FixedOgreDataManager(); + mRenderManager = new MyGUI::ShaderBasedRenderManager(); + mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index 16673ef98..eec867ff8 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,7 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; - class OgreRenderManager; + class ShaderBasedRenderManager; } namespace Ogre @@ -25,7 +25,7 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mRenderManager; Ogre::SceneManager* mSceneMgr; From d97b341dc6de0b640e55e14a5f467c5d75344b38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:02:21 -0700 Subject: [PATCH 175/817] Rename NIFMeshLoader to NIFObjectLoader --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d89d0d30a..130e94020 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1012,11 +1012,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, std::map NIFMaterialLoader::MaterialMap; -/** Manual resource loader for NIF meshes. This is the main class - responsible for translating the internal NIF mesh structure into - something Ogre can use. +/** Manual resource loader for NIF objects (meshes, particle systems, etc). + * This is the main class responsible for translating the internal NIF + * structures into something Ogre can use. */ -class NIFMeshLoader : Ogre::ManualResourceLoader +class NIFObjectLoader : Ogre::ManualResourceLoader { std::string mName; std::string mGroup; @@ -1296,7 +1296,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } - typedef std::map LoaderMap; + typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -1399,7 +1399,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } - NIFMeshLoader(const std::string &name, const std::string &group) + NIFObjectLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1421,13 +1421,13 @@ class NIFMeshLoader : Ogre::ManualResourceLoader createSubMesh(mesh, dynamic_cast(record)); } - void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) + void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) { - // Do not create meshes for the collision shape (includes all children) + // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) return; - // Marker objects: just skip the entire node + // Marker objects: just skip the entire node branch /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) return; @@ -1483,7 +1483,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { - NIFMeshLoader *loader = &sLoaders[fullname]; + NIFObjectLoader *loader = &sLoaders[fullname]; *loader = *this; loader->mShapeIndex = shape->recIndex; @@ -1543,7 +1543,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createEntities(sceneMgr, children[i].getPtr(), entities, flags); + createObjects(sceneMgr, children[i].getPtr(), entities, flags); } } } @@ -1561,7 +1561,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { - NIFMeshLoader *loader = &sLoaders[fullname]; + NIFObjectLoader *loader = &sLoaders[fullname]; *loader = *this; mesh = meshMgr.createManual(fullname, mGroup, loader); @@ -1572,7 +1572,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } public: - NIFMeshLoader() : mShapeIndex(~(size_t)0) + NIFObjectLoader() : mShapeIndex(~(size_t)0) { } static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) @@ -1601,13 +1601,13 @@ public: if(!hasSkel) hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - NIFMeshLoader meshldr(name, group); + NIFObjectLoader meshldr(name, group); if(hasSkel) meshldr.createSkelBase(sceneMgr, node, entities); - meshldr.createEntities(sceneMgr, node, entities); + meshldr.createObjects(sceneMgr, node, entities); } }; -NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; +NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) @@ -1615,7 +1615,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, EntityList entitylist; Misc::StringUtils::toLower(name); - NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); for(size_t i = 0;i < entitylist.mEntities.size();i++) { @@ -1634,7 +1634,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); bool isskinned = false; for(size_t i = 0;i < entitylist.mEntities.size();i++) From 834a6a1f009c2741465a99605f0b1a06661b0c58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:14:26 -0700 Subject: [PATCH 176/817] Remove old, unused code --- components/nifogre/ogrenifloader.cpp | 44 +--------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 130e94020..99c6a65dc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1719,46 +1719,4 @@ Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group return NIFSkeletonLoader::createSkeleton(name, group, node); } - -/* More code currently not in use, from the old D source. This was - used in the first attempt at loading NIF meshes, where each submesh - in the file was given a separate bone in a skeleton. Unfortunately - the OGRE skeletons can't hold more than 256 bones, and some NIFs go - way beyond that. The code might be of use if we implement animated - submeshes like this (the part of the NIF that is animated is - usually much less than the entire file, but the method might still - not be water tight.) - -// Insert a raw RGBA image into the texture system. -extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height, void *data) -{ - TexturePtr texture = TextureManager::getSingleton().createManual( - name, // name - "General", // group - TEX_TYPE_2D, // type - width, height, // width & height - 0, // number of mipmaps - PF_BYTE_RGBA, // pixel format - TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - // Get the pixel buffer - HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - - // Lock the pixel buffer and get a pixel box - pixelBuffer->lock(HardwareBuffer::HBL_NORMAL); // for best performance use HBL_DISCARD! - const PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - void *dest = pixelBox.data; - - // Copy the data - memcpy(dest, data, width*height*4); - - // Unlock the pixel buffer - pixelBuffer->unlock(); -} - - -*/ - -} // nsmaepace NifOgre +} // namespace NifOgre From 2db72ae607926627e95032f7e7d8f177b7da2478 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:52:35 -0700 Subject: [PATCH 177/817] Rename EntityList to ObjectList --- apps/openmw/mwrender/activatoranimation.cpp | 6 +- apps/openmw/mwrender/animation.cpp | 44 ++++++------ apps/openmw/mwrender/animation.hpp | 4 +- apps/openmw/mwrender/creatureanimation.cpp | 6 +- apps/openmw/mwrender/npcanimation.cpp | 54 +++++++-------- apps/openmw/mwrender/npcanimation.hpp | 6 +- apps/openmw/mwrender/objects.cpp | 26 +++---- apps/openmw/mwrender/sky.cpp | 18 ++--- components/nifogre/ogrenifloader.cpp | 76 ++++++++++----------- components/nifogre/ogrenifloader.hpp | 18 ++--- 10 files changed, 129 insertions(+), 129 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 961c07003..b1b820915 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -25,10 +25,10 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) { std::string mesh = "meshes\\" + ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(mPtr.getRefData().getBaseNode(), mesh); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *ent = mEntityList.mEntities[i]; + Ogre::Entity *ent = mObjectList.mEntities[i]; for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2b980320d..1d983acfc 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -40,21 +40,21 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mEntityList.mParticles.size();i++) - sceneMgr->destroyParticleSystem(mEntityList.mParticles[i]); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) - sceneMgr->destroyEntity(mEntityList.mEntities[i]); + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + sceneMgr->destroyParticleSystem(mObjectList.mParticles[i]); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) + sceneMgr->destroyEntity(mObjectList.mEntities[i]); } - mEntityList.mControllers.clear(); - mEntityList.mParticles.clear(); - mEntityList.mEntities.clear(); - mEntityList.mSkelBase = NULL; + mObjectList.mControllers.clear(); + mObjectList.mParticles.clear(); + mObjectList.mEntities.clear(); + mObjectList.mSkelBase = NULL; } void Animation::setAnimationSources(const std::vector &names) { - if(!mEntityList.mSkelBase) + if(!mObjectList.mSkelBase) return; mCurrentAnim = NULL; @@ -87,7 +87,7 @@ void Animation::setAnimationSources(const std::vector &names) if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); } mSkeletonSources.push_back(skel); @@ -105,15 +105,15 @@ void Animation::setAnimationSources(const std::vector &names) } } -void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) +void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) { mInsert = node->createChildSceneNode(); assert(mInsert); - mEntityList = NifOgre::Loader::createEntities(mInsert, model); - if(mEntityList.mSkelBase) + mObjectList = NifOgre::Loader::createObjects(mInsert, model); + if(mObjectList.mSkelBase) { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateSet *aset = mObjectList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -125,17 +125,17 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mEntityList.mControllers.size();i++) + for(size_t i = 0;i < mObjectList.mControllers.size();i++) { - if(mEntityList.mControllers[i].getSource().isNull()) - mEntityList.mControllers[i].setSource(ctrlval); + if(mObjectList.mControllers[i].getSource().isNull()) + mObjectList.mControllers[i].setSource(ctrlval); } } @@ -242,7 +242,7 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. - mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) @@ -289,7 +289,7 @@ Ogre::Vector3 Animation::updatePosition(float time) mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); else mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); - applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); + applyAnimation(mCurrentAnim, mCurrentTime, mObjectList.mSkelBase->getSkeleton()); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) @@ -465,8 +465,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mEntityList.mControllers.size();i++) - mEntityList.mControllers[i].update(); + for(size_t i = 0;i < mObjectList.mControllers.size();i++) + mObjectList.mControllers[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3e7dee6db..55aaca427 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -40,7 +40,7 @@ protected: MWMechanics::CharacterController *mController; Ogre::SceneNode* mInsert; - NifOgre::EntityList mEntityList; + NifOgre::ObjectList mObjectList; std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; @@ -91,7 +91,7 @@ protected: setAnimationSources(names); } - void createEntityList(Ogre::SceneNode *node, const std::string &model); + void createObjectList(Ogre::SceneNode *node, const std::string &model); public: Animation(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 22f84ee01..a8c4afc4e 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -25,10 +25,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), model); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(mPtr.getRefData().getBaseNode(), model); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *ent = mEntityList.mEntities[i]; + Ogre::Entity *ent = mObjectList.mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b7bcad599..5d14440e7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -50,7 +50,7 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - removeEntities(mEntityParts[i]); + removeObjects(mObjectParts[i]); } @@ -94,10 +94,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - createEntityList(node, smodel); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(node, smodel); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *base = mEntityList.mEntities[i]; + Ogre::Entity *base = mObjectList.mEntities[i]; base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if (mVisibilityFlags != 0) @@ -302,11 +302,11 @@ void NpcAnimation::updateParts(bool forceupdate) } } -NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename) +NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { - NifOgre::EntityList entities = NifOgre::Loader::createEntities(mEntityList.mSkelBase, bonename, - mInsert, mesh); - std::vector &parts = entities.mEntities; + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, + mInsert, model); + const std::vector &parts = objects.mEntities; for(size_t i = 0;i < parts.size();i++) { parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); @@ -319,9 +319,9 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - if(entities.mSkelBase) + if(objects.mSkelBase) { - Ogre::AnimationStateSet *aset = entities.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -329,12 +329,12 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int state->setEnabled(false); state->setLoop(false); } - Ogre::SkeletonInstance *skelinst = entities.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = objects.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } - return entities; + return objects; } Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) @@ -347,10 +347,10 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); + const Ogre::SkeletonInstance *skelsrc = mObjectList.mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { - Ogre::Entity *ent = mEntityParts[i].mSkelBase; + Ogre::Entity *ent = mObjectParts[i].mSkelBase; if(!ent) continue; updateSkeletonInstance(skelsrc, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); @@ -358,19 +358,19 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) return ret; } -void NpcAnimation::removeEntities(NifOgre::EntityList &entities) +void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) { - assert(&entities != &mEntityList); + assert(&objects != &mObjectList); Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < entities.mParticles.size();i++) - sceneMgr->destroyParticleSystem(entities.mParticles[i]); - for(size_t i = 0;i < entities.mEntities.size();i++) - sceneMgr->destroyEntity(entities.mEntities[i]); - entities.mControllers.clear(); - entities.mParticles.clear(); - entities.mEntities.clear(); - entities.mSkelBase = NULL; + for(size_t i = 0;i < objects.mParticles.size();i++) + sceneMgr->destroyParticleSystem(objects.mParticles[i]); + for(size_t i = 0;i < objects.mEntities.size();i++) + sceneMgr->destroyEntity(objects.mEntities[i]); + objects.mControllers.clear(); + objects.mParticles.clear(); + objects.mEntities.clear(); + objects.mSkelBase = NULL; } void NpcAnimation::removeIndividualPart(int type) @@ -382,7 +382,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeEntities(mEntityParts[i]); + removeObjects(mObjectParts[i]); break; } } @@ -420,7 +420,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - mEntityParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); + mObjectParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); break; } } @@ -451,7 +451,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorgetSkeleton()->getBone("Bip01 Head"); + return mObjectList.mSkelBase->getSkeleton()->getBone("Bip01 Head"); } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 5da4afef8..41c29f763 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -33,7 +33,7 @@ private: int mStateID; // Bounded Parts - NifOgre::EntityList mEntityParts[sPartListSize]; + NifOgre::ObjectList mObjectParts[sPartListSize]; const ESM::NPC *mNpc; std::string mHeadModel; @@ -60,11 +60,11 @@ private: int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[sPartListSize]; - NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); + NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename); void updateParts(bool forceupdate = false); - void removeEntities(NifOgre::EntityList &entities); + void removeObjects(NifOgre::ObjectList &objects); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 8c5d4cad3..3456e1c16 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -130,9 +130,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::EntityList entities = NifOgre::Loader::createEntities(insert, mesh); - for(size_t i = 0;i < entities.mEntities.size();i++) - bounds.merge(entities.mEntities[i]->getWorldBoundingBox(true)); + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(insert, mesh); + for(size_t i = 0;i < objects.mEntities.size();i++) + bounds.merge(objects.mEntities[i]->getWorldBoundingBox(true)); Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); @@ -149,9 +149,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool mBounds[ptr.getCell()].merge(bounds); bool anyTransparency = false; - for(size_t i = 0;!anyTransparency && i < entities.mEntities.size();i++) + for(size_t i = 0;!anyTransparency && i < objects.mEntities.size();i++) { - Ogre::Entity *ent = entities.mEntities[i]; + Ogre::Entity *ent = objects.mEntities[i]; for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i) { anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent(); @@ -159,11 +159,11 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool } if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || - anyTransparency || entities.mParticles.size() > 0) + anyTransparency || objects.mParticles.size() > 0) { - for(size_t i = 0;i < entities.mEntities.size();i++) + for(size_t i = 0;i < objects.mEntities.size();i++) { - Ogre::Entity *ent = entities.mEntities[i]; + Ogre::Entity *ent = objects.mEntities[i]; for(unsigned int i=0; i < ent->getNumSubEntities(); ++i) { Ogre::SubEntity* subEnt = ent->getSubEntity(i); @@ -172,9 +172,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } - for(size_t i = 0;i < entities.mParticles.size();i++) + for(size_t i = 0;i < objects.mParticles.size();i++) { - Ogre::ParticleSystem *part = entities.mParticles[i]; + Ogre::ParticleSystem *part = objects.mParticles[i]; // TODO: Check the particle system's material for actual transparency part->setRenderQueueGroup(RQG_Alpha); part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); @@ -225,8 +225,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool sg->setRenderQueueGroup(RQG_Main); - std::vector::reverse_iterator iter = entities.mEntities.rbegin(); - while(iter != entities.mEntities.rend()) + std::vector::reverse_iterator iter = objects.mEntities.rbegin(); + while(iter != objects.mEntities.rend()) { Ogre::Node *node = (*iter)->getParentNode(); sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); @@ -239,7 +239,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool if (light) { - insertLight(ptr, entities.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); + insertLight(ptr, objects.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); } } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 94af3521b..7f3abce70 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -288,10 +288,10 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::Loader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); - for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); + for(size_t i = 0, matidx = 0;i < objects.mEntities.size();i++) { - Entity* night1_ent = entities.mEntities[i]; + Entity* night1_ent = objects.mEntities[i]; night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); @@ -314,10 +314,10 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::Loader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); - for(size_t i = 0;i < entities.mEntities.size();i++) + objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); + for(size_t i = 0;i < objects.mEntities.size();i++) { - Entity* atmosphere_ent = entities.mEntities[i]; + Entity* atmosphere_ent = objects.mEntities[i]; atmosphere_ent->setCastShadows(false); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); @@ -332,10 +332,10 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::Loader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); - for(size_t i = 0;i < entities.mEntities.size();i++) + objects = NifOgre::Loader::createObjects(clouds_node, "meshes\\sky_clouds_01.nif"); + for(size_t i = 0;i < objects.mEntities.size();i++) { - Entity* clouds_ent = entities.mEntities[i]; + Entity* clouds_ent = objects.mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 99c6a65dc..e7d1a88d1 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1421,7 +1421,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader createSubMesh(mesh, dynamic_cast(record)); } - void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) + void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags=0) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -1460,12 +1460,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::SharedPtr > srcval; /* Filled in later */ Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); - entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } @@ -1494,16 +1494,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::Entity *entity = sceneMgr->createEntity(mesh); entity->setVisible(!(flags&0x01)); - entities.mEntities.push_back(entity); - if(entities.mSkelBase) + objectlist.mEntities.push_back(entity); + if(objectlist.mSkelBase) { if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(entities.mSkelBase); + entity->shareSkeletonInstanceWith(objectlist.mSkelBase); else { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); - entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } } @@ -1519,7 +1519,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); - entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } @@ -1528,11 +1528,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) { - Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); + Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) { partsys->setVisible(!(flags&0x01)); - entities.mParticles.push_back(partsys); + objectlist.mParticles.push_back(partsys); } } @@ -1543,12 +1543,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(sceneMgr, children[i].getPtr(), entities, flags); + createObjects(sceneMgr, children[i].getPtr(), objectlist, flags); } } } - void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities) + void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all @@ -1567,15 +1567,15 @@ class NIFObjectLoader : Ogre::ManualResourceLoader mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - entities.mSkelBase = sceneMgr->createEntity(mesh); - entities.mEntities.push_back(entities.mSkelBase); + objectlist.mSkelBase = sceneMgr->createEntity(mesh); + objectlist.mEntities.push_back(objectlist.mSkelBase); } public: NIFObjectLoader() : mShapeIndex(~(size_t)0) { } - static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) + static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) { Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); @@ -1603,44 +1603,44 @@ public: NIFObjectLoader meshldr(name, group); if(hasSkel) - meshldr.createSkelBase(sceneMgr, node, entities); - meshldr.createObjects(sceneMgr, node, entities); + meshldr.createSkelBase(sceneMgr, node, objectlist); + meshldr.createObjects(sceneMgr, node, objectlist); } }; NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; -EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) +ObjectList Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { - EntityList entitylist; + ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group); - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(!entity->isAttached()) parentNode->attachObject(entity); } - return entitylist; + return objectlist; } -EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, const std::string &group) +ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, const std::string &group) { - EntityList entitylist; + ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group); bool isskinned = false; - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *ent = entitylist.mEntities[i]; - if(entitylist.mSkelBase != ent && ent->hasSkeleton()) + Ogre::Entity *ent = objectlist.mEntities[i]; + if(objectlist.mSkelBase != ent && ent->hasSkeleton()) { isskinned = true; break; @@ -1655,12 +1655,12 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen { std::string filter = "@shape=tri "+bonename; Misc::StringUtils::toLower(filter); - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(entity->hasSkeleton()) { - if(entity == entitylist.mSkelBase || + if(entity == objectlist.mSkelBase || entity->getMesh()->getName().find(filter) != std::string::npos) parentNode->attachObject(entity); } @@ -1673,9 +1673,9 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } else { - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(!entity->isAttached()) { Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); @@ -1684,7 +1684,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } } - return entitylist; + return objectlist; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 819b4d880..ee50aa86e 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -39,7 +39,7 @@ namespace NifOgre typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; -struct EntityList { +struct ObjectList { Ogre::Entity *mSkelBase; std::vector mEntities; @@ -47,7 +47,7 @@ struct EntityList { std::vector > mControllers; - EntityList() : mSkelBase(0) + ObjectList() : mSkelBase(0) { } }; @@ -55,14 +55,14 @@ struct EntityList { class Loader { public: - static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); + static ObjectList createObjects(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, + const std::string &group="General"); - static EntityList createEntities(Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); + static ObjectList createObjects(Ogre::SceneNode *parentNode, + std::string name, + const std::string &group="General"); static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); }; From 878b4c15c5631fa3daa75a80d1fd44cb7e917a36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 02:08:33 -0700 Subject: [PATCH 178/817] Set visibility flags and the render queue group for particles --- apps/openmw/mwrender/activatoranimation.cpp | 9 ++++++- apps/openmw/mwrender/creatureanimation.cpp | 8 ++++++ apps/openmw/mwrender/npcanimation.cpp | 30 ++++++++++++++++----- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index b1b820915..4630208b4 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -1,6 +1,7 @@ #include "activatoranimation.hpp" #include +#include #include #include @@ -29,14 +30,20 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) for(size_t i = 0;i < mObjectList.mEntities.size();i++) { Ogre::Entity *ent = mObjectList.mEntities[i]; + ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { Ogre::SubEntity* subEnt = ent->getSubEntity(j); subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } + } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + part->setVisibilityFlags(RV_Misc); - ent->setVisibilityFlags(RV_Misc); + part->setRenderQueueGroup(RQG_Alpha); } setAnimationSource(mesh); } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index a8c4afc4e..c714a2372 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,6 +1,7 @@ #include "creatureanimation.hpp" #include +#include #include #include @@ -37,6 +38,13 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + part->setVisibilityFlags(RV_Actors); + + part->setRenderQueueGroup(RQG_Alpha); + } std::vector names; if((ref->mBase->mFlags&ESM::Creature::Biped)) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5d14440e7..28c78fd2f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -109,6 +110,15 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + + part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); + if(mVisibilityFlags != 0) + part->setVisibilityFlags(mVisibilityFlags); + part->setRenderQueueGroup(RQG_Alpha); + } std::vector skelnames(1, smodel); if(!mNpc->isMale() && !isBeast) @@ -306,19 +316,25 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in { NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, mInsert, model); - const std::vector &parts = objects.mEntities; - for(size_t i = 0;i < parts.size();i++) + for(size_t i = 0;i < objects.mEntities.size();i++) { - parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if (mVisibilityFlags != 0) - parts[i]->setVisibilityFlags(mVisibilityFlags); + objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + if(mVisibilityFlags != 0) + objects.mEntities[i]->setVisibilityFlags(mVisibilityFlags); - for(unsigned int j=0; j < parts[i]->getNumSubEntities(); ++j) + for(unsigned int j=0; j < objects.mEntities[i]->getNumSubEntities(); ++j) { - Ogre::SubEntity* subEnt = parts[i]->getSubEntity(j); + Ogre::SubEntity* subEnt = objects.mEntities[i]->getSubEntity(j); subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < objects.mParticles.size();i++) + { + objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + if(mVisibilityFlags != 0) + objects.mParticles[i]->setVisibilityFlags(mVisibilityFlags); + objects.mParticles[i]->setRenderQueueGroup(RQG_Alpha); + } if(objects.mSkelBase) { Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); From be419bc89185c74be619d08054e94e8aad0cec71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 02:28:15 -0700 Subject: [PATCH 179/817] Handle NiCamera nodes --- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 1 + components/nifogre/ogrenifloader.cpp | 8 ++++++++ components/nifogre/ogrenifloader.hpp | 7 ++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1d983acfc..23d2d9e1b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,6 +46,7 @@ Animation::~Animation() sceneMgr->destroyEntity(mObjectList.mEntities[i]); } mObjectList.mControllers.clear(); + mObjectList.mCameras.clear(); mObjectList.mParticles.clear(); mObjectList.mEntities.clear(); mObjectList.mSkelBase = NULL; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 28c78fd2f..931b8ef83 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -384,6 +384,7 @@ void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) for(size_t i = 0;i < objects.mEntities.size();i++) sceneMgr->destroyEntity(objects.mEntities[i]); objects.mControllers.clear(); + objects.mCameras.clear(); objects.mParticles.clear(); objects.mEntities.clear(); objects.mSkelBase = NULL; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e7d1a88d1..7dd616e4e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -498,6 +498,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles )) @@ -1452,6 +1453,13 @@ class NIFObjectLoader : Ogre::ManualResourceLoader e = e->extra; } + if(node->recType == Nif::RC_NiCamera) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, node->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mCameras.push_back(trgtbone); + } + Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index ee50aa86e..88cbaf691 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -42,9 +42,14 @@ static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct ObjectList { Ogre::Entity *mSkelBase; std::vector mEntities; - std::vector mParticles; + // We could actually have Ogre::Camera objects, but that means more + // maintenance when switching cameras. The information in the NiCamera node + // is pretty much useless too anyway. So instead, this is just a list of + // bones in the mSkelBase which are NiCamera nodes. + std::vector mCameras; + std::vector > mControllers; ObjectList() : mSkelBase(0) From ff1d908af416d8301dda9f1f82d8947c1213d4f4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 15:17:35 +0200 Subject: [PATCH 180/817] added script table --- apps/esmtool/record.cpp | 2 +- apps/opencs/model/world/data.cpp | 15 +++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadscpt.cpp | 15 +++++++++++++-- components/esm/loadscpt.hpp | 5 ++++- 10 files changed, 56 insertions(+), 5 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a6f77862e..e16ade6e2 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1182,7 +1182,7 @@ void Record::print() std::cout << " Variable: " << *vit << std::endl; std::cout << " ByteCode: "; - std::vector::iterator cit; + std::vector::iterator cit; for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); cit++) std::cout << boost::format("%02X") % (int)(*cit); std::cout << std::endl; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 69109bd74..c29cdaccf 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -84,6 +84,9 @@ CSMWorld::Data::Data() mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); mSounds.addColumn (new SoundFileColumn); + mScripts.addColumn (new StringIdColumn); + mScripts.addColumn (new RecordStateColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -91,6 +94,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); + addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); } CSMWorld::Data::~Data() @@ -169,6 +173,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSounds() return mSounds; } +const CSMWorld::IdCollection& CSMWorld::Data::getScripts() const +{ + return mScripts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getScripts() +{ + return mScripts; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -210,6 +224,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_FACT: mFactions.load (reader, base); break; case ESM::REC_RACE: mRaces.load (reader, base); break; case ESM::REC_SOUN: mSounds.load (reader, base); break; + case ESM::REC_SCPT: mScripts.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 320480e63..7daf5d4ba 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -30,6 +31,7 @@ namespace CSMWorld IdCollection mFactions; IdCollection mRaces; IdCollection mSounds; + IdCollection mScripts; std::vector mModels; std::map mModelIndex; @@ -74,6 +76,10 @@ namespace CSMWorld IdCollection& getSounds(); + const IdCollection& getScripts() const; + + IdCollection& getScripts(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 7bdc15c8c..816681a13 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -24,6 +24,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -37,6 +38,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index a21d67fcd..06db75d7f 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -47,7 +47,9 @@ namespace CSMWorld Type_Races, Type_Race, Type_Sounds, - Type_Sound + Type_Sound, + Type_Scripts, + Type_Script }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 611690ca6..27cf78b3c 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -109,6 +109,10 @@ void CSVDoc::View::setupWorldMenu() QAction *sounds = new QAction (tr ("Sounds"), this); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); world->addAction (sounds); + + QAction *scripts = new QAction (tr ("Scripts"), this); + connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView())); + world->addAction (scripts); } void CSVDoc::View::setupUi() @@ -289,6 +293,11 @@ void CSVDoc::View::addSoundsSubView() addSubView (CSMWorld::UniversalId::Type_Sounds); } +void CSVDoc::View::addScriptsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Scripts); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index e8e716b70..4822db3e4 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -125,6 +125,8 @@ namespace CSVDoc void addRacesSubView(); void addSoundsSubView(); + + void addScriptsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 3ba950f87..7cdf18bce 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -21,6 +21,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Factions, CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_Sounds, + CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index d9b6497d9..2c1b018d9 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -64,7 +64,7 @@ void Script::save(ESMWriter &esm) memcpy(data.mName.name, mId.c_str(), mId.size()); esm.writeHNT("SCHD", data, 52); - + if (!mVarNames.empty()) { esm.startSubRecord("SCVR"); @@ -76,10 +76,21 @@ void Script::save(ESMWriter &esm) } esm.startSubRecord("SCDT"); - esm.write(&mScriptData[0], mData.mScriptDataSize); + esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); esm.endRecord("SCDT"); esm.writeHNOString("SCTX", mScriptText); } + void Script::blank() + { + mData.mNumShorts = mData.mNumLongs = mData.mNumFloats = 0; + mData.mScriptDataSize = 0; + mData.mStringTableSize = 0; + + mVarNames.clear(); + mScriptData.clear(); + mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n"; + } + } diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 10a6d24b1..be7e83900 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -52,11 +52,14 @@ public: SCHDstruct mData; std::vector mVarNames; // Variable names - std::vector mScriptData; // Compiled bytecode + std::vector mScriptData; // Compiled bytecode std::string mScriptText; // Uncompiled script void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 755a80a522963f6d6b26f39134bd6696c917756c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 15:52:43 +0200 Subject: [PATCH 181/817] Fix camera shaking when near the pitch limit. --- apps/openmw/mwrender/player.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 63396378d..55fda326f 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -242,14 +242,15 @@ namespace MWRender void Player::setPitch(float angle) { - float limit = Ogre::Math::HALF_PI; + const float epsilon = 0.000001; + float limit = Ogre::Math::HALF_PI - epsilon; if (mVanity.forced || mPreviewMode) { limit /= 2; } if (angle > limit) { - angle = limit - 0.01; + angle = limit; } else if (angle < -limit) { - angle = -limit + 0.01; + angle = -limit; } if (mVanity.enabled || mPreviewMode) { mPreviewCam.pitch = angle; From ebff64a7a4b297c2b9a34a808c19d4b57ee8dee9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 06:56:12 -0700 Subject: [PATCH 182/817] Fix UVController and add warn about unhandled material controllers --- components/nifogre/ogrenifloader.cpp | 63 ++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 7dd616e4e..8924056e0 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -184,18 +184,23 @@ public: static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) { - Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); + if(keys.mKeys.size() == 0) + return def; + + if(time <= keys.mKeys.front().mTime) + return keys.mKeys.front().mValue; + + Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()+1); for(;iter != keys.mKeys.end();iter++) { - if(iter->mTime > time) + if(iter->mTime < time) continue; - Nif::FloatKeyList::VecType::const_iterator next(iter+1); - if(next == keys.mKeys.end()) - return iter->mValue; - float a = (time-iter->mTime) / (next->mTime-iter->mTime); - return iter->mValue + ((next->mValue - iter->mValue)*a); + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); } - return def; + return keys.mKeys.back().mValue; } public: @@ -837,6 +842,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, else warn("Found internal texture, ignoring."); } + + Nif::ControllerPtr ctrls = texprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled texture controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); @@ -845,6 +857,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, { alphaFlags = alphaprop->flags; alphaTest = alphaprop->data.threshold; + + Nif::ControllerPtr ctrls = alphaprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled alpha controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } // Vertex color handling @@ -853,17 +872,38 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, vertMode = vertprop->data.vertmode; // FIXME: Handle lightmode? //lightMode = vertprop->data.lightmode; + + Nif::ControllerPtr ctrls = vertprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } if(zprop) { depthFlags = zprop->flags; // Depth function??? + + Nif::ControllerPtr ctrls = zprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled depth controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } if(specprop) { specFlags = specprop->flags; + + Nif::ControllerPtr ctrls = specprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled specular controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } // Material @@ -875,6 +915,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, emissive = matprop->data.emissive; glossiness = matprop->data.glossiness; alpha = matprop->data.alpha; + + Nif::ControllerPtr ctrls = matprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled material controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } { From 2e067e95a9a63bbb25d12ecbe6fb969a4e638317 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:12:52 -0700 Subject: [PATCH 183/817] Handle NiWireframeProperty --- components/nifogre/ogrenifloader.cpp | 37 +++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8924056e0..94cb14b58 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -799,6 +799,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, const Nif::NiVertexColorProperty *vertprop, const Nif::NiZBufferProperty *zprop, const Nif::NiSpecularProperty *specprop, + const Nif::NiWireframeProperty *wireprop, bool &needTangents) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); @@ -819,6 +820,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, int depthFlags = 3; // Default should be 1, but Bloodmoon's models are broken int specFlags = 0; + int wireFlags = 0; Ogre::String texName[7]; bool vertexColour = (shapedata->colors.size() != 0); @@ -906,6 +908,18 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, } } + if(wireprop) + { + wireFlags = wireprop->flags; + + Nif::ControllerPtr ctrls = wireprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + // Material if(matprop) { @@ -950,6 +964,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, boost::hash_combine(h, vertMode); boost::hash_combine(h, depthFlags); boost::hash_combine(h, specFlags); + boost::hash_combine(h, wireFlags); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -993,6 +1008,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } + if(wireFlags) + { + instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); + } + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); @@ -1087,10 +1107,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiAlphaProperty *&alphaprop, const Nif::NiVertexColorProperty *&vertprop, const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop) + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *wireprop) { if(node->parent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); const Nif::PropertyList &proplist = node->props; for(size_t i = 0;i < proplist.length();i++) @@ -1112,6 +1133,8 @@ class NIFObjectLoader : Ogre::ManualResourceLoader zprop = static_cast(pr); else if(pr->recType == Nif::RC_NiSpecularProperty) specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } @@ -1324,13 +1347,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, - needTangents); + wireprop, needTangents); if(matname.length() > 0) sub->setMaterialName(matname); @@ -1405,13 +1429,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, - needTangents)); + wireprop, needTangents)); partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); partsys->setCullIndividually(false); From 8bbfba3f43afa56d62c63b310700384d50fcfaa4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 16:18:40 +0200 Subject: [PATCH 184/817] Fix fatigue not being set to its maximum value when player is rebuilt --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8757213e9..4a2a2ecc6 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -149,7 +149,7 @@ namespace MWMechanics // forced update and current value adjustments mActors.updateActor (ptr, 0); - for (int i=0; i<2; ++i) + for (int i=0; i<3; ++i) { DynamicStat stat = creatureStats.getDynamic (i); stat.setCurrent (stat.getModified()); From e25f5c6dfe71b5c076ccd01dce5048f575ac5aa5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 16:32:06 +0200 Subject: [PATCH 185/817] added basic region table --- apps/opencs/model/world/data.cpp | 16 ++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadregn.cpp | 19 ++++++++++++++++--- components/esm/loadregn.hpp | 3 +++ 9 files changed, 58 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c29cdaccf..0c6f2b4ad 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -87,6 +87,10 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); + mRegions.addColumn (new StringIdColumn); + mRegions.addColumn (new RecordStateColumn); + mRegions.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -95,6 +99,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); + addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); } CSMWorld::Data::~Data() @@ -183,6 +188,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getScripts() return mScripts; } +const CSMWorld::IdCollection& CSMWorld::Data::getRegions() const +{ + return mRegions; +} + +CSMWorld::IdCollection& CSMWorld::Data::getRegions() +{ + return mRegions; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -225,6 +240,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_RACE: mRaces.load (reader, base); break; case ESM::REC_SOUN: mSounds.load (reader, base); break; case ESM::REC_SCPT: mScripts.load (reader, base); break; + case ESM::REC_REGN: mRegions.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 7daf5d4ba..d9432aa3e 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -32,6 +33,7 @@ namespace CSMWorld IdCollection mRaces; IdCollection mSounds; IdCollection mScripts; + IdCollection mRegions; std::vector mModels; std::map mModelIndex; @@ -80,6 +82,10 @@ namespace CSMWorld IdCollection& getScripts(); + const IdCollection& getRegions() const; + + IdCollection& getRegions(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 816681a13..4a81ee01b 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -25,6 +25,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -39,6 +40,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 06db75d7f..507febba4 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -49,7 +49,9 @@ namespace CSMWorld Type_Sounds, Type_Sound, Type_Scripts, - Type_Script + Type_Script, + Type_Regions, + Type_Region }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 27cf78b3c..8e51ba9dc 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -113,6 +113,10 @@ void CSVDoc::View::setupWorldMenu() QAction *scripts = new QAction (tr ("Scripts"), this); connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView())); world->addAction (scripts); + + QAction *regions = new QAction (tr ("Regions"), this); + connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); + world->addAction (regions); } void CSVDoc::View::setupUi() @@ -298,6 +302,11 @@ void CSVDoc::View::addScriptsSubView() addSubView (CSMWorld::UniversalId::Type_Scripts); } +void CSVDoc::View::addRegionsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Regions); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 4822db3e4..a5190dedc 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -127,6 +127,8 @@ namespace CSVDoc void addSoundsSubView(); void addScriptsSubView(); + + void addRegionsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 7cdf18bce..30812f8f5 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -22,6 +22,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_Scripts, + CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index d39a29454..41c7f507a 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -31,14 +31,14 @@ void Region::load(ESMReader &esm) void Region::save(ESMWriter &esm) { esm.writeHNCString("FNAM", mName); - + if (esm.getVersion() == VER_12) esm.writeHNT("WEAT", mData, sizeof(mData) - 2); else esm.writeHNT("WEAT", mData); - + esm.writeHNOCString("BNAM", mSleepList); - + esm.writeHNT("CNAM", mMapColor); for (std::vector::iterator it = mSoundList.begin(); it != mSoundList.end(); ++it) { @@ -46,4 +46,17 @@ void Region::save(ESMWriter &esm) } } + void Region::blank() + { + mName.clear(); + + mData.mClear = mData.mCloudy = mData.mFoggy = mData.mOvercast = mData.mRain = + mData.mThunder = mData.mAsh, mData.mBlight = mData.mA = mData.mB = 0; + + mMapColor = 0; + + mName.clear(); + mSleepList.clear(); + mSoundList.clear(); + } } diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 0496ef5af..f2a3d9a10 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -48,6 +48,9 @@ struct Region void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 88c81bfb243164d185723dfbe8e266bf58611034 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:38:43 -0700 Subject: [PATCH 186/817] Apply polygon_mode to objects --- files/materials/objects.mat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 49df4e394..957d75db5 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -17,6 +17,7 @@ material openmw_objects_base depth_check default alpha_rejection default transparent_sorting default + polygon_mode default pass { @@ -41,6 +42,7 @@ material openmw_objects_base depth_write $depth_write depth_check $depth_check transparent_sorting $transparent_sorting + polygon_mode $polygon_mode texture_unit diffuseMap { From fe9a7f12b6c21bc6dc4ebc8ac22fb5fc767a0b81 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:53:01 -0700 Subject: [PATCH 187/817] Material fixes --- components/nifogre/ogrenifloader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 94cb14b58..3bd8b95e5 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -947,9 +947,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, boost::hash_combine(h, diffuse.x); boost::hash_combine(h, diffuse.y); boost::hash_combine(h, diffuse.z); + boost::hash_combine(h, alpha); boost::hash_combine(h, specular.x); boost::hash_combine(h, specular.y); boost::hash_combine(h, specular.z); + boost::hash_combine(h, glossiness); boost::hash_combine(h, emissive.x); boost::hash_combine(h, emissive.y); boost::hash_combine(h, emissive.z); @@ -1108,7 +1110,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *&vertprop, const Nif::NiZBufferProperty *&zprop, const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *wireprop) + const Nif::NiWireframeProperty *&wireprop) { if(node->parent) getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); From f49a2a97c5f09a30703448b28cadbe17adf963ce Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 16:56:21 +0200 Subject: [PATCH 188/817] added map colour column to region table --- apps/opencs/model/world/columns.hpp | 34 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 35 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 75dfe15c2..b09c931b2 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -5,6 +5,8 @@ #include +#include + #include "columnbase.hpp" namespace CSMWorld @@ -591,6 +593,38 @@ namespace CSMWorld return true; } }; + + /// \todo QColor is a GUI class and should not be in model. Need to think of an alternative + /// solution. + template + struct MapColourColumn : public Column + { + /// \todo Replace Display_Integer with something that displays the colour value more directly. + MapColourColumn() : Column ("Map Colour", ColumnBase::Display_Integer) {} + + virtual QVariant get (const Record& record) const + { + int colour = record.get().mMapColor; + + return QColor (colour & 0xff, (colour>>8) & 0xff, (colour>>16) & 0xff); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + QColor colour = data.value(); + + record2.mMapColor = colour.rgb() & 0xffffff; + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0c6f2b4ad..f45165687 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -90,6 +90,7 @@ CSMWorld::Data::Data() mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); mRegions.addColumn (new NameColumn); + mRegions.addColumn (new MapColourColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From ab5980ae187b8e8e71167353368c0598a83bc26f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 08:29:56 -0700 Subject: [PATCH 189/817] Let the default controller function use absolute input And convert the VisController to use it. --- components/nifogre/ogrenifloader.cpp | 84 ++++++++++++++-------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3bd8b95e5..e5e072620 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -75,24 +75,33 @@ private: float mStopTime; public: - DefaultFunction(const Nif::Controller *ctrl) - : Ogre::ControllerFunction(false) + DefaultFunction(const Nif::Controller *ctrl, bool deltaInput) + : Ogre::ControllerFunction(deltaInput) , mFrequency(ctrl->frequency) , mPhase(ctrl->phase) , mStartTime(ctrl->timeStart) , mStopTime(ctrl->timeStop) { - mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); + if(mDeltaInput) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } } virtual Ogre::Real calculate(Ogre::Real value) { - mDeltaCount += value*mFrequency; - mDeltaCount = std::fmod(mDeltaCount - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; + if(mDeltaInput) + { + mDeltaCount += value*mFrequency; + mDeltaCount = std::fmod(mDeltaCount - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + + value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); + return value; } }; @@ -103,6 +112,20 @@ public: { private: Ogre::Bone *mTarget; + std::vector mData; + + virtual bool calculate(Ogre::Real time) + { + if(mData.size() == 0) + return true; + + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > time) + return mData[i-1].isSet; + } + return mData.back().isSet; + } // FIXME: We are not getting all objects here. Skinned meshes get // attached to the object's root node, and won't be connected via a @@ -126,7 +149,9 @@ public: } public: - Value(Ogre::Bone *target) : mTarget(target) + Value(Ogre::Bone *target, const Nif::NiVisData *data) + : mTarget(target) + , mData(data->mVis) { } virtual Ogre::Real getValue() const @@ -135,39 +160,14 @@ public: return 1.0f; } - virtual void setValue(Ogre::Real value) + virtual void setValue(Ogre::Real time) { - int vis = static_cast(value); + bool vis = calculate(time); setVisible(mTarget, vis); } }; - class Function : public Ogre::ControllerFunction - { - private: - std::vector mData; - - public: - Function(const Nif::NiVisData *data) - : Ogre::ControllerFunction(false), - mData(data->mVis) - { } - - virtual Ogre::Real calculate(Ogre::Real value) - { - if(mData.size() == 0) - return 1.0f; - - if(mData[0].time >= value) - return mData[0].isSet; - for(size_t i = 1;i < mData.size();i++) - { - if(mData[i].time > value) - return mData[i-1].isSet; - } - return mData.back().isSet; - } - }; + typedef DefaultFunction Function; }; class UVController @@ -1543,9 +1543,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::SharedPtr > srcval; /* Filled in later */ - Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); - Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, false)); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -1599,7 +1599,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, true)); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } From 399394ff103ec1f2779cdb8244caccff6da5621e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 10:03:13 -0700 Subject: [PATCH 190/817] Don't restrict animations to the keyframe time limits --- components/nifogre/ogrenifloader.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e5e072620..90139c9f0 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -384,10 +384,8 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const lasttrans = curtrans = traniter->mValue; if(scaleiter != scalekeys.mKeys.end()) lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - float begTime = std::max(kfc->timeStart, startTime); - float endTime = std::min(kfc->timeStop, stopTime); - bool didlast = false; + bool didlast = false; while(!didlast) { float curtime = std::numeric_limits::max(); @@ -400,11 +398,11 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const if(scaleiter != scalekeys.mKeys.end()) curtime = std::min(curtime, scaleiter->mTime); - curtime = std::max(curtime, begTime); - if(curtime >= endTime) + curtime = std::max(curtime, startTime); + if(curtime >= stopTime) { didlast = true; - curtime = endTime; + curtime = stopTime; } // Get the latest quaternions, translations, and scales for the From 822866b5ae325a8a6a1bf29d1c09f4c8860f9104 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 7 Apr 2013 18:04:30 +0100 Subject: [PATCH 191/817] fixed autorun --- apps/openmw/mwinput/inputmanagerimp.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 74d581b81..0ed49cd7f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -301,6 +301,12 @@ namespace MWInput mPlayer.setForwardBackward (-1); } + else if(mPlayer.getAutoMove()) + { + triedToMove = true; + mPlayer.setForwardBackward (1); + } + mPlayer.setSneak(actionIsActive(A_Sneak)); if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) @@ -321,6 +327,7 @@ namespace MWInput mOverencumberedMessageDelay -= dt; if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) { + mPlayer.setAutoMove (false); if (mOverencumberedMessageDelay <= 0) { MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); From c9424f577f15a35a6f1fe22d6681db39a48269fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 19:29:15 +0200 Subject: [PATCH 192/817] added sleeplist column to region table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b09c931b2..aa097dac6 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -625,6 +625,31 @@ namespace CSMWorld return true; } }; + + template + struct SleepListColumn : public Column + { + SleepListColumn() : Column ("Sleep Encounter", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mSleepList.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mSleepList = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f45165687..fc93675e4 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -91,6 +91,7 @@ CSMWorld::Data::Data() mRegions.addColumn (new RecordStateColumn); mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); + mRegions.addColumn (new SleepListColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 593646436ea4fe3dcabdb01b40c2fd5d45b0a279 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 19:39:13 +0200 Subject: [PATCH 193/817] added verifier for region record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/regioncheck.cpp | 33 +++++++++++++++++++++++++ apps/opencs/model/tools/regioncheck.hpp | 29 ++++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/regioncheck.cpp create mode 100644 apps/opencs/model/tools/regioncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ffd4c7f1e..301febfc4 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck ) diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp new file mode 100644 index 000000000..ac64ac027 --- /dev/null +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -0,0 +1,33 @@ + +#include "regioncheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::RegionCheckStage::RegionCheckStage (const CSMWorld::IdCollection& regions) +: mRegions (regions) +{} + +int CSMTools::RegionCheckStage::setup() +{ + return mRegions.getSize(); +} + +void CSMTools::RegionCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Region& region = mRegions.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Region, region.mId); + + // test for empty name + if (region.mName.empty()) + messages.push_back (id.toString() + "|" + region.mId + " has an empty name"); + + /// \todo test that the ID in mSleeplist exists + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/regioncheck.hpp b/apps/opencs/model/tools/regioncheck.hpp new file mode 100644 index 000000000..b42135651 --- /dev/null +++ b/apps/opencs/model/tools/regioncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_REGIONCHECK_H +#define CSM_TOOLS_REGIONCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that region records are internally consistent + class RegionCheckStage : public Stage + { + const CSMWorld::IdCollection& mRegions; + + public: + + RegionCheckStage (const CSMWorld::IdCollection& regions); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 4003bc884..45adcf5e4 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -17,6 +17,7 @@ #include "factioncheck.hpp" #include "racecheck.hpp" #include "soundcheck.hpp" +#include "regioncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -66,6 +67,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); + + mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); } return mVerifier; From 80a1abd48ad5bc37e604c820249d8d7d250cd91c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 11:09:55 -0700 Subject: [PATCH 194/817] Clear the old text keys when setting new animation sources --- apps/openmw/mwrender/animation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 23d2d9e1b..8ecebc707 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -63,6 +63,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimVelocity = 0.0f; mAccumRoot = NULL; mNonAccumRoot = NULL; + mTextKeys.clear(); mSkeletonSources.clear(); std::vector::const_iterator nameiter; @@ -96,7 +97,7 @@ void Animation::setAnimationSources(const std::vector &names) { Ogre::Animation *anim = skel->getAnimation(i); const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); + "@"+anim->getName()); if(!groupdata.isEmpty()) mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); } From 60cc95305d101c820856684186b7fb3beabf1e8f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 20:26:39 +0200 Subject: [PATCH 195/817] added basic birthsign table --- apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadbsgn.cpp | 8 ++++++++ components/esm/loadbsgn.hpp | 3 +++ 9 files changed, 51 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fc93675e4..70162ba75 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -93,6 +93,11 @@ CSMWorld::Data::Data() mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); + mBirthsigns.addColumn (new StringIdColumn); + mBirthsigns.addColumn (new RecordStateColumn); + mBirthsigns.addColumn (new NameColumn); + mBirthsigns.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -102,6 +107,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); + addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); } CSMWorld::Data::~Data() @@ -200,6 +206,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getRegions() return mRegions; } +const CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() const +{ + return mBirthsigns; +} + +CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() +{ + return mBirthsigns; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -243,6 +259,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SOUN: mSounds.load (reader, base); break; case ESM::REC_SCPT: mScripts.load (reader, base); break; case ESM::REC_REGN: mRegions.load (reader, base); break; + case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index d9432aa3e..122e855d8 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -34,6 +35,7 @@ namespace CSMWorld IdCollection mSounds; IdCollection mScripts; IdCollection mRegions; + IdCollection mBirthsigns; std::vector mModels; std::map mModelIndex; @@ -86,6 +88,10 @@ namespace CSMWorld IdCollection& getRegions(); + const IdCollection& getBirthsigns() const; + + IdCollection& getBirthsigns(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 4a81ee01b..6d305d6c0 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -26,6 +26,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -41,6 +42,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 507febba4..0586719f1 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -51,7 +51,9 @@ namespace CSMWorld Type_Scripts, Type_Script, Type_Regions, - Type_Region + Type_Region, + Type_Birthsigns, + Type_Birthsign }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 8e51ba9dc..af9b81420 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -117,6 +117,10 @@ void CSVDoc::View::setupWorldMenu() QAction *regions = new QAction (tr ("Regions"), this); connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); world->addAction (regions); + + QAction *birthsigns = new QAction (tr ("Birthsigns"), this); + connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView())); + world->addAction (birthsigns); } void CSVDoc::View::setupUi() @@ -307,6 +311,11 @@ void CSVDoc::View::addRegionsSubView() addSubView (CSMWorld::UniversalId::Type_Regions); } +void CSVDoc::View::addBirthsignsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Birthsigns); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index a5190dedc..12944e569 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -129,6 +129,8 @@ namespace CSVDoc void addScriptsSubView(); void addRegionsSubView(); + + void addBirthsignsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 30812f8f5..23c66319c 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -23,6 +23,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_Regions, + CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index b58071644..cb500f674 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -24,4 +24,12 @@ void BirthSign::save(ESMWriter &esm) mPowers.save(esm); } + void BirthSign::blank() + { + mName.clear(); + mDescription.clear(); + mTexture.clear(); + mPowers.mList.clear(); + } + } diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index b0bc28be4..434ddf68e 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -20,6 +20,9 @@ struct BirthSign void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From baf8eaecb82f75168eaac998c9795faa18c3b72e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 20:46:04 +0200 Subject: [PATCH 196/817] added texture column to birthsign table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index aa097dac6..fbc533779 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -650,6 +650,31 @@ namespace CSMWorld return true; } }; + + template + struct TextureColumn : public Column + { + TextureColumn() : Column ("Texture", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mTexture.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mTexture = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 70162ba75..b385c5b4c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -96,6 +96,7 @@ CSMWorld::Data::Data() mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); mBirthsigns.addColumn (new NameColumn); + mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); From 2d2196b0d60d4b874af143e370547e72d14ef3ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:01:02 +0200 Subject: [PATCH 197/817] Implemented levelled items --- apps/openmw/mwworld/containerstore.cpp | 73 ++++++++++++++++++++++---- apps/openmw/mwworld/containerstore.hpp | 1 + components/esm/loadlevlist.hpp | 15 +++--- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index a377f2bbb..8a5662986 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -14,6 +14,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" @@ -180,21 +182,72 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { - ManualRef ref (store, iter->mItem.toString()); - - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) - { - /// \todo implement leveled item lists - continue; - } - - ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) - addImp (ref.getPtr()); + std::string id = iter->mItem.toString(); + addInitialItem(id, iter->mCount); } flagAsModified(); } +void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, unsigned char failChance, bool topLevel) +{ + count = std::abs(count); /// \todo implement item restocking (indicated by negative count) + + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); + + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + { + const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; + const std::vector& items = levItem->mList; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); + + failChance += levItem->mChanceNone; + + if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) + { + for (int i=0; i (std::rand()) / RAND_MAX; + if (random >= failChance/100.f) + { + std::vector candidates; + int highestLevel = 0; + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (it->mLevel > highestLevel) + highestLevel = it->mLevel; + } + + std::pair highest = std::make_pair(-1, ""); + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (playerLevel >= it->mLevel + && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + { + candidates.push_back(it->mId); + if (it->mLevel >= highest.first) + highest = std::make_pair(it->mLevel, it->mId); + } + + } + if (!candidates.size()) + return; + std::string item = candidates[std::rand()%candidates.size()]; + addInitialItem(item, count, failChance, false); + } + } + else + { + ref.getPtr().getRefData().setCount (count); + addImp (ref.getPtr()); + } +} + void MWWorld::ContainerStore::clear() { for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 9d315d27f..a466c3c2a 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -53,6 +53,7 @@ namespace MWWorld mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr); + void addInitialItem (const std::string& id, int count, unsigned char failChance=0, bool topLevel=true); public: diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index b7db5db36..aa9656d72 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -22,17 +22,20 @@ struct LeveledListBase { enum Flags { - AllLevels = 0x01, // Calculate from all levels <= player - // level, not just the closest below - // player. - Each = 0x02 // Select a new item each time this + + Each = 0x01, // Select a new item each time this // list is instantiated, instead of // giving several identical items - }; // (used when a container has more + // (used when a container has more // than one instance of one leveled // list.) + AllLevels = 0x02 // Calculate from all levels <= player + // level, not just the closest below + // player. + }; + int mFlags; - unsigned char mChanceNone; // Chance that none are selected (0-255?) + unsigned char mChanceNone; // Chance that none are selected (0-100) std::string mId; // Record name used to read references. Must be set before load() is From f3c8cd2065ee3f781d3259464e7b1b2943f1f842 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:38:53 +0200 Subject: [PATCH 198/817] Don't buy/sell keys which are set to open a lock --- apps/openmw/mwclass/apparatus.cpp | 5 +++++ apps/openmw/mwclass/apparatus.hpp | 2 ++ apps/openmw/mwclass/armor.cpp | 5 +++++ apps/openmw/mwclass/armor.hpp | 2 ++ apps/openmw/mwclass/book.cpp | 5 +++++ apps/openmw/mwclass/book.hpp | 2 ++ apps/openmw/mwclass/clothing.cpp | 5 +++++ apps/openmw/mwclass/clothing.hpp | 2 ++ apps/openmw/mwclass/ingredient.cpp | 5 +++++ apps/openmw/mwclass/ingredient.hpp | 2 ++ apps/openmw/mwclass/light.cpp | 5 +++++ apps/openmw/mwclass/light.hpp | 2 ++ apps/openmw/mwclass/lockpick.cpp | 5 +++++ apps/openmw/mwclass/lockpick.hpp | 2 ++ apps/openmw/mwclass/misc.cpp | 8 ++++++++ apps/openmw/mwclass/misc.hpp | 2 ++ apps/openmw/mwclass/potion.cpp | 5 +++++ apps/openmw/mwclass/potion.hpp | 2 ++ apps/openmw/mwclass/probe.cpp | 5 +++++ apps/openmw/mwclass/probe.hpp | 2 ++ apps/openmw/mwclass/repair.cpp | 5 +++++ apps/openmw/mwclass/repair.hpp | 2 ++ apps/openmw/mwclass/weapon.cpp | 5 +++++ apps/openmw/mwclass/weapon.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 27 +-------------------------- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ components/esm/loadnpc.hpp | 2 +- 28 files changed, 97 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 851a5ae36..32c127731 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -159,4 +159,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mAppas.insert(*ref), &cell); } + + bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Apparatus; + } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 7045f62d6..d4917c618 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -54,6 +54,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 320944d3c..e62985d3d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -315,4 +315,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Armor; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 65f49abb7..16905d65c 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -74,6 +74,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 85b006160..b658295f8 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -183,4 +183,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Books; + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 29e3de036..3f083f552 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -59,6 +59,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index abad26767..98480f06f 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -262,4 +262,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Clothing; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index c3ef22f11..2e5bb424f 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -68,6 +68,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 14cf6ff6f..0afe60e0e 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -197,4 +197,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mIngreds.insert(*ref), &cell); } + + bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Ingredients; + } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 0afd202fb..d27a7cbb0 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -56,6 +56,8 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 746665772..306c6bbb6 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -203,4 +203,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mLights.insert(*ref), &cell); } + + bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Lights; + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 640e1705b..7d919f75d 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 201572696..bfbf10756 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -176,4 +176,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mLockpicks.insert(*ref), &cell); } + + bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Picks; + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 0961b55b2..edd884a3e 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8cfac1a68..02307cc02 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -246,4 +246,12 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionSoulgem(ptr)); } + bool Miscellaneous::canSell (const MWWorld::Ptr& item, int npcServices) const + { + MWWorld::LiveCellRef *ref = + item.get(); + + return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc); + } + } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 12a50af19..ba00900bd 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -53,6 +53,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 37461ed90..ad2826ea8 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -194,4 +194,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mPotions.insert(*ref), &cell); } + + bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Potions; + } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index d595f7e69..845795d0e 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -52,6 +52,8 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index e4533af65..4ec6a8340 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -175,4 +175,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mProbes.insert(*ref), &cell); } + + bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Probes; + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index d9f90baf6..75ebaa01c 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index bafedee88..36e706825 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -175,4 +175,9 @@ namespace MWClass { return boost::shared_ptr(new MWWorld::ActionRepair(ptr)); } + + bool Repair::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::RepairItem; + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 3083c97e3..a545cf4d6 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -61,6 +61,8 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exceoption) + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0a527262f..3df1ced7d 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -409,4 +409,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Weapon::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Weapon; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 4774bb50b..084ceeca2 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -73,6 +73,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 81a29e69b..73904371e 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -356,32 +356,7 @@ namespace MWGui services = ref->mBase->mAiData.mServices; } - /// \todo what about potions, there doesn't seem to be a flag for them?? - - if (item.getTypeName() == typeid(ESM::Weapon).name()) - return services & ESM::NPC::Weapon; - else if (item.getTypeName() == typeid(ESM::Armor).name()) - return services & ESM::NPC::Armor; - else if (item.getTypeName() == typeid(ESM::Clothing).name()) - return services & ESM::NPC::Clothing; - else if (item.getTypeName() == typeid(ESM::Book).name()) - return services & ESM::NPC::Books; - else if (item.getTypeName() == typeid(ESM::Ingredient).name()) - return services & ESM::NPC::Ingredients; - else if (item.getTypeName() == typeid(ESM::Lockpick).name()) - return services & ESM::NPC::Picks; - else if (item.getTypeName() == typeid(ESM::Probe).name()) - return services & ESM::NPC::Probes; - else if (item.getTypeName() == typeid(ESM::Light).name()) - return services & ESM::NPC::Lights; - else if (item.getTypeName() == typeid(ESM::Apparatus).name()) - return services & ESM::NPC::Apparatus; - else if (item.getTypeName() == typeid(ESM::Repair).name()) - return services & ESM::NPC::RepairItem; - else if (item.getTypeName() == typeid(ESM::Miscellaneous).name()) - return services & ESM::NPC::Misc; - - return false; + return MWWorld::Class::get(item).canSell(item, services); } std::vector TradeWindow::itemsToIgnore() diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2dfa241b3..0f8d40e93 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -47,6 +47,11 @@ namespace MWWorld throw std::runtime_error ("class does not represent an actor"); } + bool Class::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return false; + } + MWMechanics::CreatureStats& Class::getCreatureStats (const Ptr& ptr) const { throw std::runtime_error ("class does not have creature stats"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index de4741e38..49e0ff003 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -238,6 +238,9 @@ namespace MWWorld virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const; + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices + virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 46be29961..b30077f23 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -35,11 +35,11 @@ struct NPC Apparatus = 0x00100, RepairItem = 0x00200, Misc = 0x00400, + Potions = 0x02000, // Other services Spells = 0x00800, MagicItems = 0x01000, - Potions = 0x02000, Training = 0x04000, // What skills? Spellmaking = 0x08000, Enchanting = 0x10000, From 2362e920f309b272994cd1763f7e668fc7033de8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 12:41:27 -0700 Subject: [PATCH 199/817] Use an unconnected object list for animation sources We'll want the controllers, as the plan is to use their keyframe controllers to animate the actual skeleton used for the meshes. --- apps/openmw/mwrender/animation.cpp | 52 ++++++++++++++++++---------- apps/openmw/mwrender/animation.hpp | 3 +- components/nifogre/ogrenifloader.cpp | 29 +++------------- components/nifogre/ogrenifloader.hpp | 4 ++- 4 files changed, 42 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8ecebc707..686fbbb84 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,6 +16,19 @@ namespace MWRender { +void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) +{ + for(size_t i = 0;i < objects.mParticles.size();i++) + sceneMgr->destroyParticleSystem(objects.mParticles[i]); + for(size_t i = 0;i < objects.mEntities.size();i++) + sceneMgr->destroyEntity(objects.mEntities[i]); + objects.mControllers.clear(); + objects.mCameras.clear(); + objects.mParticles.clear(); + objects.mEntities.clear(); + objects.mSkelBase = NULL; +} + Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mController(NULL) @@ -40,16 +53,12 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mObjectList.mParticles.size();i++) - sceneMgr->destroyParticleSystem(mObjectList.mParticles[i]); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) - sceneMgr->destroyEntity(mObjectList.mEntities[i]); + destroyObjectList(sceneMgr, mObjectList); + + for(size_t i = 0;i < mAnimationSources.size();i++) + destroyObjectList(sceneMgr, mAnimationSources[i]); + mAnimationSources.clear(); } - mObjectList.mControllers.clear(); - mObjectList.mCameras.clear(); - mObjectList.mParticles.clear(); - mObjectList.mEntities.clear(); - mObjectList.mSkelBase = NULL; } @@ -57,6 +66,7 @@ void Animation::setAnimationSources(const std::vector &names) { if(!mObjectList.mSkelBase) return; + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); mCurrentAnim = NULL; mCurrentKeys = NULL; @@ -64,19 +74,24 @@ void Animation::setAnimationSources(const std::vector &names) mAccumRoot = NULL; mNonAccumRoot = NULL; mTextKeys.clear(); - mSkeletonSources.clear(); + for(size_t i = 0;i < mAnimationSources.size();i++) + destroyObjectList(sceneMgr, mAnimationSources[i]); + mAnimationSources.clear(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { - Ogre::SkeletonPtr skel = NifOgre::Loader::getSkeleton(*nameiter); - if(skel.isNull()) + mAnimationSources.push_back(NifOgre::Loader::createObjectBase(sceneMgr, *nameiter)); + if(!mAnimationSources.back().mSkelBase) { std::cerr<< "Failed to get skeleton source "<<*nameiter <touch(); + Ogre::Entity *ent = mAnimationSources.back().mSkelBase; + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { @@ -92,7 +107,6 @@ void Animation::setAnimationSources(const std::vector &names) mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); } - mSkeletonSources.push_back(skel); for(int i = 0;i < skel->getNumAnimations();i++) { Ogre::Animation *anim = skel->getAnimation(i); @@ -144,9 +158,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mSkeletonSources.begin());iter != mSkeletonSources.end();iter++) + for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) { - if((*iter)->hasAnimation(anim)) + if(iter->mSkelBase->hasAnimationState(anim)) return true; } return false; @@ -413,11 +427,11 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::const_reverse_iterator iter(mSkeletonSources.rbegin());iter != mSkeletonSources.rend();iter++) + for(std::vector::const_reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) { - if((*iter)->hasAnimation(groupname)) + if(iter->mSkelBase->hasAnimationState(groupname)) { - mCurrentAnim = (*iter)->getAnimation(groupname); + mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; mAnimVelocity = 0.0f; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 55aaca427..22ab9fc7e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -47,7 +47,7 @@ protected: Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::vector mSkeletonSources; + std::vector mAnimationSources; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -92,6 +92,7 @@ protected: } void createObjectList(Ogre::SceneNode *node, const std::string &model); + static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); public: Animation(const MWWorld::Ptr &ptr); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 90139c9f0..d3da77e41 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1768,35 +1768,14 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena } -Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group) +ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string name, const std::string &group) { - Ogre::SkeletonPtr skel; + ObjectList objectlist; Misc::StringUtils::toLower(name); - skel = Ogre::SkeletonManager::getSingleton().getByName(name); - if(!skel.isNull()) - return skel; + NIFObjectLoader::load(sceneMgr, objectlist, name, group); - Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); - if(nif->numRoots() < 1) - { - nif->warn("Found no root nodes in "+name+"."); - return skel; - } - - // The first record is assumed to be the root node - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); - - const Nif::Node *node = dynamic_cast(r); - if(node == NULL) - { - nif->warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return skel; - } - - return NIFSkeletonLoader::createSkeleton(name, group, node); + return objectlist; } } // namespace NifOgre diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 88cbaf691..3a7a22f8b 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -69,7 +69,9 @@ public: std::string name, const std::string &group="General"); - static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); + static ObjectList createObjectBase(Ogre::SceneManager *sceneMgr, + std::string name, + const std::string &group="General"); }; } From 480467b6ebf693004cbc3df2232ff981465a086f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:53:11 +0200 Subject: [PATCH 200/817] Reset the 'owner' field for items that were legitimately bought from an NPC. --- apps/openmw/mwgui/tradewindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 73904371e..7756484fa 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -257,6 +257,12 @@ namespace MWGui MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); // success! make the item transfer. + MWWorld::ContainerStore& playerBoughtItems = mWindowManager.getInventoryWindow()->getBoughtItems(); + for (MWWorld::ContainerStoreIterator it = playerBoughtItems.begin(); it != playerBoughtItems.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->getCellRef().mOwner, MWWorld::Class::get(mPtr).getId(mPtr))) + it->getCellRef().mOwner = ""; + } transferBoughtItems(); mWindowManager.getInventoryWindow()->transferBoughtItems(); From 7494f90301bcf35a6d3560b495b4f61455b05c9c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 13:02:46 -0700 Subject: [PATCH 201/817] Remove an unneeded function --- apps/openmw/mwrender/npcanimation.cpp | 21 +++------------------ apps/openmw/mwrender/npcanimation.hpp | 1 - 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 931b8ef83..253dbb0ff 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -50,8 +50,9 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize NpcAnimation::~NpcAnimation() { + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); for(size_t i = 0;i < sPartListSize;i++) - removeObjects(mObjectParts[i]); + destroyObjectList(sceneMgr, mObjectParts[i]); } @@ -374,22 +375,6 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) return ret; } -void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) -{ - assert(&objects != &mObjectList); - - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < objects.mParticles.size();i++) - sceneMgr->destroyParticleSystem(objects.mParticles[i]); - for(size_t i = 0;i < objects.mEntities.size();i++) - sceneMgr->destroyEntity(objects.mEntities[i]); - objects.mControllers.clear(); - objects.mCameras.clear(); - objects.mParticles.clear(); - objects.mEntities.clear(); - objects.mSkelBase = NULL; -} - void NpcAnimation::removeIndividualPart(int type) { mPartPriorities[type] = 0; @@ -399,7 +384,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeObjects(mObjectParts[i]); + destroyObjectList(mInsert->getCreator(), mObjectParts[i]); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 41c29f763..b59051a8d 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -64,7 +64,6 @@ private: void updateParts(bool forceupdate = false); - void removeObjects(NifOgre::ObjectList &objects); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); From 44a59e1b87805627390d44d8ba02710476445d7a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 13:03:41 -0700 Subject: [PATCH 202/817] Fix a couple messages --- components/nifogre/ogrenifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d3da77e41..d02c0816e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1092,12 +1092,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader static void warn(const std::string &msg) { - std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl; } static void fail(const std::string &msg) { - std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + std::cerr << "NIFObjectLoader: Fail: "<< msg << std::endl; abort(); } From 9e08497f0200b8ea42ad3e6116b868ebca7adbf6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 22:07:04 +0200 Subject: [PATCH 203/817] Initial container content should inherit the owner of its container --- apps/openmw/mwworld/cells.cpp | 6 +++--- apps/openmw/mwworld/containerstore.cpp | 11 ++++++----- apps/openmw/mwworld/containerstore.hpp | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 5f771be47..4838cfefa 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -45,7 +45,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, container.getCellRef().mOwner, mStore); } for (CellRefList::List::iterator iter ( @@ -55,7 +55,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, Class::get(container).getId(container), mStore); } for (CellRefList::List::iterator iter ( @@ -65,7 +65,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, Class::get(container).getId(container), mStore); } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8a5662986..05026a98b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -177,19 +177,19 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr return it; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWorld::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const MWWorld::ESMStore& store) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = iter->mItem.toString(); - addInitialItem(id, iter->mCount); + addInitialItem(id, owner, iter->mCount); } flagAsModified(); } -void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, unsigned char failChance, bool topLevel) +void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, unsigned char failChance, bool topLevel) { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) @@ -208,7 +208,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i Date: Sun, 7 Apr 2013 13:46:29 -0700 Subject: [PATCH 204/817] Update animation source controller targets --- apps/openmw/mwrender/animation.cpp | 14 ++++++++++++++ components/nifogre/ogrenifloader.cpp | 9 ++++----- components/nifogre/ogrenifloader.hpp | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 686fbbb84..f3ecbd6a5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,6 +78,7 @@ void Animation::setAnimationSources(const std::vector &names) destroyObjectList(sceneMgr, mAnimationSources[i]); mAnimationSources.clear(); + Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { @@ -89,6 +90,19 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.pop_back(); continue; } + const NifOgre::ObjectList &objects = mAnimationSources.back(); + + for(size_t i = 0;i < objects.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval = dynamic_cast*>(objects.mControllers[i].getDestination().getPointer()); + if(!dstval) continue; + + const Ogre::String &trgtname = dstval->getNode()->getName(); + if(!skelinst->hasBone(trgtname)) continue; + + Ogre::Bone *bone = skelinst->getBone(trgtname); + dstval->setNode(bone); + } Ogre::Entity *ent = mAnimationSources.back().mSkelBase; Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d02c0816e..a0aefaccc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -108,10 +108,9 @@ public: class VisController { public: - class Value : public Ogre::ControllerValue + class Value : public NodeTargetValue { private: - Ogre::Bone *mTarget; std::vector mData; virtual bool calculate(Ogre::Real time) @@ -149,8 +148,8 @@ public: } public: - Value(Ogre::Bone *target, const Nif::NiVisData *data) - : mTarget(target) + Value(Ogre::Node *target, const Nif::NiVisData *data) + : NodeTargetValue(target) , mData(data->mVis) { } @@ -163,7 +162,7 @@ public: virtual void setValue(Ogre::Real time) { bool vis = calculate(time); - setVisible(mTarget, vis); + setVisible(mNode, vis); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 3a7a22f8b..18bbf0200 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -74,6 +74,24 @@ public: const std::string &group="General"); }; +// FIXME: Should be with other general Ogre extensions. +template +class NodeTargetValue : public Ogre::ControllerValue +{ +protected: + Ogre::Node *mNode; + +public: + NodeTargetValue(Ogre::Node *target) : mNode(target) + { } + + void setNode(Ogre::Node *target) + { mNode = target; } + Ogre::Node *getNode() const + { return mNode; } +}; +typedef Ogre::SharedPtr > NodeTargetValueRealPtr; + } namespace std From 43a501369080f633f829a4b3e64e87b960d738ec Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 23:25:35 +0200 Subject: [PATCH 205/817] added verifier for birthsign record --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/tools/birthsigncheck.cpp | 39 ++++++++++++++++++++++ apps/opencs/model/tools/birthsigncheck.hpp | 29 ++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 72 insertions(+) create mode 100644 apps/opencs/model/tools/birthsigncheck.cpp create mode 100644 apps/opencs/model/tools/birthsigncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 301febfc4..87221d7af 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -36,6 +36,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck + birthsigncheck ) diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp new file mode 100644 index 000000000..b673c93de --- /dev/null +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -0,0 +1,39 @@ + +#include "birthsigncheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns) +: mBirthsigns (birthsigns) +{} + +int CSMTools::BirthsignCheckStage::setup() +{ + return mBirthsigns.getSize(); +} + +void CSMTools::BirthsignCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::BirthSign& birthsign = mBirthsigns.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId); + + // test for empty name, description and texture + if (birthsign.mName.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty name"); + + if (birthsign.mDescription.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty description"); + + if (birthsign.mTexture.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " is missing a texture"); + + /// \todo test if the texture exists + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/birthsigncheck.hpp b/apps/opencs/model/tools/birthsigncheck.hpp new file mode 100644 index 000000000..42b5a6b24 --- /dev/null +++ b/apps/opencs/model/tools/birthsigncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_BIRTHSIGNCHECK_H +#define CSM_TOOLS_BIRTHSIGNCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that birthsign records are internally consistent + class BirthsignCheckStage : public Stage + { + const CSMWorld::IdCollection& mBirthsigns; + + public: + + BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 45adcf5e4..78796de41 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -18,6 +18,7 @@ #include "racecheck.hpp" #include "soundcheck.hpp" #include "regioncheck.hpp" +#include "birthsigncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -69,6 +70,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); + + mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); } return mVerifier; From 261ea1fe5e137386e4b859bcbae6b519d4fa3b1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 14:56:23 -0700 Subject: [PATCH 206/817] Implement a KeyframeController --- apps/openmw/mwrender/animation.cpp | 21 ++++-- apps/openmw/mwrender/animation.hpp | 1 + components/nifogre/ogrenifloader.cpp | 107 +++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f3ecbd6a5..fd7aeac1d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -37,6 +37,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) , mLastPosition(0.0f) + , mCurrentControllers(NULL) , mCurrentKeys(NULL) , mCurrentAnim(NULL) , mCurrentTime(0.0f) @@ -68,6 +69,7 @@ void Animation::setAnimationSources(const std::vector &names) return; Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + mCurrentControllers = &mObjectList.mControllers; mCurrentAnim = NULL; mCurrentKeys = NULL; mAnimVelocity = 0.0f; @@ -78,6 +80,7 @@ void Animation::setAnimationSources(const std::vector &names) destroyObjectList(sceneMgr, mAnimationSources[i]); mAnimationSources.clear(); + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) @@ -90,7 +93,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.pop_back(); continue; } - const NifOgre::ObjectList &objects = mAnimationSources.back(); + NifOgre::ObjectList &objects = mAnimationSources.back(); for(size_t i = 0;i < objects.mControllers.size();i++) { @@ -104,7 +107,13 @@ void Animation::setAnimationSources(const std::vector &names) dstval->setNode(bone); } - Ogre::Entity *ent = mAnimationSources.back().mSkelBase; + for(size_t i = 0;i < objects.mControllers.size();i++) + { + if(objects.mControllers[i].getSource().isNull()) + objects.mControllers[i].setSource(ctrlval); + } + + Ogre::Entity *ent = objects.mSkelBase; Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -167,6 +176,7 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model if(mObjectList.mControllers[i].getSource().isNull()) mObjectList.mControllers[i].setSource(ctrlval); } + mCurrentControllers = &mObjectList.mControllers; } @@ -441,12 +451,13 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::const_reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) + for(std::vector::reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) { if(iter->mSkelBase->hasAnimationState(groupname)) { mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; if(mNonAccumRoot) @@ -495,8 +506,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mObjectList.mControllers.size();i++) - mObjectList.mControllers[i].update(); + for(size_t i = 0;i < mCurrentControllers->size();i++) + (*mCurrentControllers)[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 22ab9fc7e..aee139bd6 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -49,6 +49,7 @@ protected: std::vector mAnimationSources; + std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a0aefaccc..e7bf820b8 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -169,6 +169,101 @@ public: typedef DefaultFunction Function; }; +class KeyframeController +{ +public: + class Value : public NodeTargetValue + { + private: + Nif::QuaternionKeyList mRotations; + Nif::Vector3KeyList mTranslations; + Nif::FloatKeyList mScales; + + public: + Value(Ogre::Node *target, const Nif::NiKeyframeData *data) + : NodeTargetValue(target) + , mRotations(data->mRotations) + , mTranslations(data->mTranslations) + , mScales(data->mScales) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 0.0f; + } + + virtual void setValue(Ogre::Real time) + { + if(mRotations.mKeys.size() > 0) + { + if(time <= mRotations.mKeys.front().mTime) + mNode->setOrientation(mRotations.mKeys.front().mValue); + else if(time >= mRotations.mKeys.back().mTime) + mNode->setOrientation(mRotations.mKeys.back().mValue); + else + { + Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); + for(;iter != mRotations.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); + break; + } + } + } + if(mTranslations.mKeys.size() > 0) + { + if(time <= mTranslations.mKeys.front().mTime) + mNode->setPosition(mTranslations.mKeys.front().mValue); + else if(time >= mTranslations.mKeys.back().mTime) + mNode->setPosition(mTranslations.mKeys.back().mValue); + else + { + Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); + for(;iter != mTranslations.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::Vector3KeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); + break; + } + } + } + if(mScales.mKeys.size() > 0) + { + if(time <= mScales.mKeys.front().mTime) + mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); + else if(time >= mScales.mKeys.back().mTime) + mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); + else + { + Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); + for(;iter != mScales.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); + break; + } + } + } + } + }; + + typedef DefaultFunction Function; +}; + class UVController { public: @@ -1546,6 +1641,18 @@ class NIFObjectLoader : Ogre::ManualResourceLoader objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } + else if(ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } ctrl = ctrl->next; } From 3c633e275e99852ea48e8b8e1e49f3145c63e640 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 15:42:07 -0700 Subject: [PATCH 207/817] Don't create a controller for empty keyframe data --- components/nifogre/ogrenifloader.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e7bf820b8..e06a23b5b 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1644,14 +1644,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader else if(ctrl->recType == Nif::RC_NiKeyframeController) { const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } } ctrl = ctrl->next; } From 7baca30a1d10bd0cef7b49e59be39e7df92692e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 16:21:45 -0700 Subject: [PATCH 208/817] Only get the non-accum root's keyframe when updating positions The actual animation pose is now handled by the controllers, based on the current animation time. --- apps/openmw/mwrender/animation.cpp | 80 ++++++++++++++---------------- apps/openmw/mwrender/animation.hpp | 9 ++-- 2 files changed, 40 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fd7aeac1d..72f7ebaf2 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -263,28 +263,6 @@ void Animation::calcAnimVelocity() } } -void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) -{ - Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); - Ogre::Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator(); - while(tracks.hasMoreElements()) - { - Ogre::NodeAnimationTrack *track = tracks.getNext(); - const Ogre::String &targetname = track->getAssociatedNode()->getName(); - if(!skel->hasBone(targetname)) - continue; - Ogre::Bone *bone = skel->getBone(targetname); - bone->setOrientation(Ogre::Quaternion::IDENTITY); - bone->setPosition(Ogre::Vector3::ZERO); - bone->setScale(Ogre::Vector3::UNIT_SCALE); - track->applyToNode(bone, timeindex); - } - - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); -} - static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) { if(skelsrc->hasBone(bone->getName())) @@ -323,24 +301,29 @@ void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Og } -Ogre::Vector3 Animation::updatePosition(float time) +Ogre::Vector3 Animation::updatePosition() { - if(mLooping) - mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); - else - mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); - applyAnimation(mCurrentAnim, mCurrentTime, mObjectList.mSkelBase->getSkeleton()); + Ogre::Vector3 posdiff; - Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; - if(mNonAccumRoot) + Ogre::TransformKeyFrame kf(0, mCurrentTime); + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(trackiter.hasMoreElements()) { - /* Get the non-accumulation root's difference from the last update. */ - posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; - - /* Translate the accumulation root back to compensate for the move. */ - mLastPosition += posdiff; - mAccumRoot->setPosition(-mLastPosition); + const Ogre::NodeAnimationTrack *track = trackiter.getNext(); + if(track->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + { + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); + break; + } } + + /* Get the non-accumulation root's difference from the last update. */ + posdiff = (kf.getTranslate() - mLastPosition) * mAccumulate; + + /* Translate the accumulation root back to compensate for the move. */ + mLastPosition += posdiff; + mAccumRoot->setPosition(-mLastPosition); + return posdiff; } @@ -486,11 +469,14 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) timepassed *= mAnimSpeedMult; while(mCurrentAnim && mPlaying) { - float targetTime = std::min(mStopTime, mCurrentTime+timepassed); + float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - movement += updatePosition(targetTime); - mPlaying = (mLooping || mStopTime > targetTime); + mCurrentTime = std::min(mStopTime, targetTime); + if(mNonAccumRoot) + movement += updatePosition(); + mPlaying = (mLooping || mStopTime > mCurrentTime); + timepassed = targetTime - mCurrentTime; break; } @@ -498,10 +484,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) const std::string &evt = mNextKey->second; mNextKey++; - movement += updatePosition(time); - mPlaying = (mLooping || mStopTime > time); - - timepassed = targetTime - time; + mCurrentTime = time; + if(mNonAccumRoot) + movement += updatePosition(); + mPlaying = (mLooping || mStopTime > mCurrentTime); + timepassed = targetTime - mCurrentTime; if(!handleEvent(time, evt)) break; @@ -509,6 +496,13 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) for(size_t i = 0;i < mCurrentControllers->size();i++) (*mCurrentControllers)[i].update(); + if(mObjectList.mSkelBase) + { + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + } + return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index aee139bd6..2fcc1e8f7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -63,16 +63,13 @@ protected: void calcAnimVelocity(); - /* Applies the given animation to the given skeleton instance, using the specified time. */ - void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); - /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); - /* Updates the animation to the specified time, and returns the movement - * vector since the last update or reset. */ - Ogre::Vector3 updatePosition(float time); + /* Updates the position of the accum root node for the current time, and + * returns the wanted movement vector from the previous update. */ + Ogre::Vector3 updatePosition(); /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If From dba7308248ef270a5a138c2f0470b9412e13e414 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 17:16:49 -0700 Subject: [PATCH 209/817] Recognize NiParticleRotation --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e06a23b5b..ac1e8e056 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1487,13 +1487,17 @@ class NIFObjectLoader : Ogre::ManualResourceLoader affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } + else if(e->recType == Nif::RC_NiParticleRotation) + { + // TODO: Implement (Ogre::RotationAffector?) + } else if(e->recType == Nif::RC_NiParticleColorModifier) { // TODO: Implement (Ogre::ColourInterpolatorAffector?) } else if(e->recType == Nif::RC_NiGravity) { - // TODO: Implement (Ogre::LinearForceAffector?) + // TODO: Implement } else warn("Unhandled particle modifier "+e->recName); From c6c67a1bb49d22d93f6c9f6bf5859ddc4c5629f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 18:15:23 -0700 Subject: [PATCH 210/817] Read NiGravity fields --- components/nif/controlled.hpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 08c47defe..6acb8ff20 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -98,12 +98,23 @@ public: class NiGravity : public Controlled { public: + float mForce; + /* 0 - Wind (fixed direction) + * 1 - Point (fixed origin) + */ + int mType; + Ogre::Vector3 mPosition; + Ogre::Vector3 mDirection; + void read(NIFStream *nif) { Controlled::read(nif); - // two floats, one int, six floats - nif->skip(9*4); + /*unknown*/nif->getFloat(); + mForce = nif->getFloat(); + mType = nif->getUInt(); + mPosition = nif->getVector3(); + mDirection = nif->getVector3(); } }; From 08d43fe21787501b5a572c946268e8e2874b2410 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 05:48:52 -0700 Subject: [PATCH 211/817] Make the getHeadNode method more general --- apps/openmw/mwrender/animation.cpp | 12 ++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 5 ----- apps/openmw/mwrender/npcanimation.hpp | 2 -- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 72f7ebaf2..067e85672 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -180,6 +180,18 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model } +Ogre::Node *Animation::getNode(const std::string &name) +{ + if(mObjectList.mSkelBase) + { + Ogre::SkeletonInstance *skel = mObjectList.mSkelBase->getSkeleton(); + if(skel->hasBone(name)) + return skel->getBone(name); + } + return NULL; +} + + bool Animation::hasAnimation(const std::string &anim) { for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2fcc1e8f7..cfef28f16 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -113,6 +113,8 @@ public: void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); + + Ogre::Node *getNode(const std::string &name); }; } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 843bcf007..616543a7d 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -201,7 +201,7 @@ namespace MWRender void RaceSelectionPreview::updateCamera() { Ogre::Vector3 scale = mNode->getScale(); - Ogre::Vector3 headOffset = mAnimation->getHeadNode()->_getDerivedPosition(); + Ogre::Vector3 headOffset = mAnimation->getNode("Bip01 Head")->_getDerivedPosition(); headOffset = mNode->convertLocalToWorldPosition(headOffset); mCamera->setPosition(headOffset + mPosition * scale); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 253dbb0ff..d7620a8de 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -451,9 +451,4 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorgetSkeleton()->getBone("Bip01 Head"); -} - } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index b59051a8d..224d174f4 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -78,8 +78,6 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); - Ogre::Node* getHeadNode(); - void forceUpdate() { updateParts(true); } }; From a5c868c9f58c26210da7f818fd4449acb7a9a7e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 14:54:19 +0200 Subject: [PATCH 212/817] Create a separate vertex buffer for each UV set --- components/nifogre/ogrenifloader.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8f9d69f6e..a94f46901 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -992,17 +992,19 @@ class NIFMeshLoader : Ogre::ManualResourceLoader size_t numUVs = data->uvlist.size(); if(numUVs) { - size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); - vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size()*numUVs, - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); for(size_t i = 0;i < numUVs;i++) { + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + const std::vector &uvlist = data->uvlist[i]; - vbuf->writeData(i*srcVerts.size()*elemSize, elemSize*srcVerts.size(), &uvlist[0], true); - decl->addElement(nextBuf, i*srcVerts.size()*elemSize, Ogre::VET_FLOAT2, + + vbuf->writeData(0, elemSize*srcVerts.size(), &uvlist[0], true); + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + bind->setBinding(nextBuf++, vbuf); } - bind->setBinding(nextBuf++, vbuf); } // Triangle faces From 343e2027af0797db178967ca36765d26373ac138 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 15:17:30 +0200 Subject: [PATCH 213/817] Support NIF detail maps --- components/nifogre/ogrenifloader.cpp | 15 ++++++++++++++- files/materials/objects.mat | 16 +++++++++++++--- files/materials/objects.shader | 17 +++++++++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a94f46901..9244ac6cc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -749,16 +749,29 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) { instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); } + if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) + { + instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) + { + // force automips on normal maps for now + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); + } + for(int i = 1;i < 7;i++) { - if(!texName[i].empty()) + if(!texName[i].empty() && (i == Nif::NiTexturingProperty::DarkTexture || i == Nif::NiTexturingProperty::DecalTexture + || i == Nif::NiTexturingProperty::GlossTexture)) warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); } diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 49df4e394..994a18ea9 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -9,9 +9,10 @@ material openmw_objects_base normalMap emissiveMap use_emissive_map false + use_detail_map false emissiveMapUVSet 0 + detailMapUVSet 0 - is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default depth_write default depth_check default @@ -26,10 +27,11 @@ material openmw_objects_base shader_properties { vertexcolor_mode $vertmode - is_transparent $is_transparent normalMap $normalMap emissiveMapUVSet $emissiveMapUVSet + detailMapUVSet $detailMapUVSet emissiveMap $emissiveMap + detailMap $detailMap } diffuse $diffuse @@ -51,7 +53,7 @@ material openmw_objects_base texture_unit normalMap { - direct_texture $normalMap + texture $normalMap } texture_unit emissiveMap @@ -61,6 +63,14 @@ material openmw_objects_base direct_texture $emissiveMap tex_coord_set $emissiveMapUVSet } + + texture_unit detailMap + { + create_in_ffp $use_detail_map + colour_op_ex modulate_x2 src_current src_texture + direct_texture $detailMap + tex_coord_set $detailMapUVSet + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index d0e817373..aa7f006a2 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -16,9 +16,10 @@ #define NORMAL_MAP @shPropertyHasValue(normalMap) #define EMISSIVE_MAP @shPropertyHasValue(emissiveMap) +#define DETAIL_MAP @shPropertyHasValue(detailMap) // right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more -#define SECOND_UV_SET @shPropertyString(emissiveMapUVSet) +#define SECOND_UV_SET (@shPropertyString(emissiveMapUVSet) || @shPropertyString(detailMapUVSet)) // if normal mapping is enabled, we force pixel lighting #define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) @@ -236,6 +237,10 @@ shSampler2D(emissiveMap) #endif +#if DETAIL_MAP + shSampler2D(detailMap) +#endif + shInput(float4, UV) #if NORMAL_MAP @@ -313,6 +318,14 @@ { shOutputColour(0) = shSample(diffuseMap, UV.xy); +#if DETAIL_MAP +#if @shPropertyString(detailMapUVSet) + shOutputColour(0) *= shSample(detailMap, UV.zw)*2; +#else + shOutputColour(0) *= shSample(detailMap, UV.xy)*2; +#endif +#endif + #if NORMAL_MAP float3 normal = normalPassthrough; float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); @@ -419,7 +432,7 @@ #endif #if EMISSIVE_MAP - #if SECOND_UV_SET + #if @shPropertyString(emissiveMapUVSet) shOutputColour(0).xyz += shSample(emissiveMap, UV.zw).xyz; #else shOutputColour(0).xyz += shSample(emissiveMap, UV.xy).xyz; From a7de870a443bb602ea45515f312ed730f46045b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 16:21:18 +0200 Subject: [PATCH 214/817] Fix mercenary not updating its profit when item was dragged onto the player avatar --- apps/openmw/mwgui/inventorywindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 001f42bd1..c744fcf6d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -150,6 +150,7 @@ namespace MWGui it = invStore.add(ptr); (*it).getRefData().setCount(mDragAndDrop->mDraggedCount); ptr = *it; + mDragAndDrop->mDraggedFrom->notifyItemDragged(ptr, -mDragAndDrop->mDraggedCount); } /// \todo scripts From d0bcf830919ec034f40f213404be618bc588fefc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 16:30:18 +0200 Subject: [PATCH 215/817] Adjust player position to ground after using travel services --- apps/openmw/mwgui/travelwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 465f588b8..2508498fa 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -156,6 +156,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->advanceTime(time); } MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); + MWWorld::Class::get(player).adjustPosition(player); mWindowManager.removeGuiMode(GM_Travel); mWindowManager.removeGuiMode(GM_Dialogue); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0); From 50932a7a6bf52281aaa37242e53d0d84739a80ac Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 17:50:03 +0200 Subject: [PATCH 216/817] Finished bugfix #691 --- apps/openmw/mwclass/armor.cpp | 47 ++++++++++++++------------------ apps/openmw/mwclass/clothing.cpp | 31 ++++++++++++--------- apps/openmw/mwclass/weapon.cpp | 42 +++++++--------------------- 3 files changed, 49 insertions(+), 71 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 496e69545..f6392941d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -321,15 +321,10 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { + std::vector parts = it->get()->mBase->mParts.mParts; + if(*slot == MWWorld::InventoryStore::Slot_Helmet) { - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - - bool allow = true; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_Head) @@ -337,41 +332,41 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - allow = false; - break; + return false; } } - - if(!allow) - break; } if (*slot == MWWorld::InventoryStore::Slot_Boots) { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - allow = false; - // Only notify the player, not npcs if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - } - break; + return false; } } - - if(!allow) - return false; } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + return true; } } return true; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 77a7557bf..318515a7b 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -267,32 +267,37 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { + std::vector parts = it->get()->mBase->mParts.mParts; + + if(*slot == MWWorld::InventoryStore::Slot_Helmet) + { + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_Head) + { + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); + + return false; + } + } + } + if (*slot == MWWorld::InventoryStore::Slot_Boots) { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - allow = false; - // Only notify the player, not npcs if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); } - break; + + return false; } } - - if(!allow) - return false; } - } } return true; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 51e813003..a0a8b7e87 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -411,41 +411,19 @@ namespace MWClass { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - } - } - } - if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) - { - MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); } + return true; } - return true; } return false; } From 194ca2584dfced9e807c1c5865eb3b5600a723e0 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 17:53:41 +0200 Subject: [PATCH 217/817] Small azura's star fix --- apps/openmw/mwmechanics/enchanting.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d92acdafc..a38cb0037 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -53,14 +53,18 @@ namespace MWMechanics bool Enchanting::create() { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); - //Exception for Azura Star, it's not destroyed after enchanting + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + + //Exception for Azura Star, new one will be added after enchanting if(boost::iequals(mSoulGemPtr.get()->mBase->mId, "Misc_SoulGem_Azura")) - mSoulGemPtr.getCellRef().mSoul=""; - else - mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + { + MWWorld::ManualRef azura (MWBase::Environment::get().getWorld()->getStore(), "Misc_SoulGem_Azura"); + MWWorld::Class::get (player).getContainerStore (player).add (azura.getPtr()); + } if(mSelfEnchanting) { @@ -87,7 +91,6 @@ namespace MWMechanics MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); ref.getPtr().getRefData().setCount (mOldItemCount-1); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); if(!mSelfEnchanting) payForEnchantment(); From 23097ac9dc3b0046471bb1ebce1238dc5a97af61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 09:47:03 -0700 Subject: [PATCH 218/817] Minor cleanup of NiMorphData --- components/nif/data.hpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 0804b53ae..bd109041f 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -398,16 +398,13 @@ struct NiMorphData : public Record { int morphCount = nif->getInt(); int vertCount = nif->getInt(); - nif->getChar(); + /*relative targets?*/nif->getChar(); mMorphs.resize(morphCount); for(int i = 0;i < morphCount;i++) { mMorphs[i].mData.read(nif, true); - - mMorphs[i].mVertices.resize(vertCount); - for(int j = 0;j < vertCount;j++) - mMorphs[i].mVertices[j] = nif->getVector3(); + nif->getVector3s(mMorphs[i].mVertices, vertCount); } } }; From 2f52df22cea1558074457146f67b8e22516e5976 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 19:00:38 +0200 Subject: [PATCH 219/817] Bugfix #553 --- apps/openmw/mwgui/journalwindow.cpp | 6 ------ apps/openmw/mwgui/journalwindow.hpp | 1 - apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++++ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index ba39b0101..f33cfd353 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -114,15 +114,9 @@ MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) //displayLeftText(list.front()); } -void MWGui::JournalWindow::close() -{ - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); -} - void MWGui::JournalWindow::open() { mPageNumber = 0; - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) { book journal; diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cd1ff7ebb..f68cca46e 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -16,7 +16,6 @@ namespace MWGui public: JournalWindow(MWBase::WindowManager& parWindowManager); virtual void open(); - virtual void close(); private: void displayLeftText(std::string text); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0ed49cd7f..c23106be1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -656,9 +656,15 @@ namespace MWInput bool gameMode = !mWindows.isGuiMode(); if(gameMode) + { + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); mWindows.pushGuiMode(MWGui::GM_Journal); + } else if(mWindows.getMode() == MWGui::GM_Journal) + { + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); mWindows.popGuiMode(); + } // .. but don't touch any other mode. } From 7c22e123f4c6fb37f27f874749096a4b9a8b4558 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 22:10:55 +0200 Subject: [PATCH 220/817] Bugfix #691 changes --- apps/openmw/mwclass/armor.cpp | 27 +++++------------ apps/openmw/mwclass/armor.hpp | 3 +- apps/openmw/mwclass/clothing.cpp | 24 ++++------------ apps/openmw/mwclass/clothing.hpp | 3 +- apps/openmw/mwclass/weapon.cpp | 40 +++++++------------------- apps/openmw/mwclass/weapon.hpp | 3 +- apps/openmw/mwworld/actionequip.cpp | 11 +++++-- apps/openmw/mwworld/class.cpp | 4 +-- apps/openmw/mwworld/class.hpp | 4 +-- apps/openmw/mwworld/inventorystore.cpp | 13 +++++++-- 10 files changed, 53 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index f6392941d..ddab6f754 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,25 +292,13 @@ namespace MWClass ref->mBase = record; } - bool Armor::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Armor::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - std::string npcRace = npc.get()->mBase->mRace; for (std::vector::const_iterator slot=slots.first.begin(); @@ -321,7 +309,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = it->get()->mBase->mParts.mParts; + std::vector parts = item.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { @@ -332,7 +320,7 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - return false; + return 0; } } } @@ -345,7 +333,7 @@ namespace MWClass { if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - return false; + return 0; } } } @@ -363,13 +351,12 @@ namespace MWClass weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + return 3; } - return true; + return 1; } } - return true; + return 1; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index bb07e42b0..96c72848c 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 318515a7b..58c4a2c5c 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,25 +238,11 @@ namespace MWClass ref->mBase = record; } - bool Clothing::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Clothing::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); - // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - std::string npcRace = npc.get()->mBase->mRace; for (std::vector::const_iterator slot=slots.first.begin(); @@ -267,7 +253,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = it->get()->mBase->mParts.mParts; + std::vector parts = item.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { @@ -278,7 +264,7 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - return false; + return 0; } } } @@ -294,13 +280,13 @@ namespace MWClass MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); } - return false; + return 0; } } } } } - return true; + return 1; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 4978fa228..eb8d80199 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,7 +61,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a0a8b7e87..a0cacaf6b 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,48 +384,30 @@ namespace MWClass ref->mBase = record; } - bool Weapon::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Weapon::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); - - // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - - std::string npcRace = npc.get()->mBase->mRace; - // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + if(item.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + item.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + item.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + item.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + return 2; } - return true; + return 1; } } - return false; + return 0; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 922cd165f..01686b09c 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,7 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index c147113fc..51d0de6fe 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,8 +43,15 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - if(!MWWorld::Class::get(getTarget()).canEquip(actor,getTarget())) - break; + switch(MWWorld::Class::get (*it).canBeEquipped (actor, *it)) + { + case 0: + return; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index ee2072cf0..a0067f5d2 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,9 +259,9 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - bool Class::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Class::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - return true; + return 1; } void Class::adjustPosition(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 4931da7a8..362a8bc9c 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,8 +242,8 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; - ///< Return 0 if player cannot equip item. Unequip twohanded item if neccesary + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 7a5ae38d0..9f51db353 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -131,6 +131,8 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) { const MWMechanics::NpcStats& stats = MWWorld::Class::get(npc).getNpcStats(npc); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + TSlots slots; initSlots (slots); @@ -184,8 +186,15 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - if(!MWWorld::Class::get (test).canEquip (npc, test)) - continue; + switch(MWWorld::Class::get (test).canBeEquipped (npc, test)) + { + case 0: + continue; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { From e7c0f2a211b4854b6ce6198c5245a6071483b0da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 14:54:13 -0700 Subject: [PATCH 221/817] Minor cleanup to loading texture UV coords --- components/nifogre/ogrenifloader.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index aa28a30dd..bf4621e6f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1400,21 +1400,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader // Texture UV coordinates size_t numUVs = data->uvlist.size(); - if(numUVs) + for(size_t i = 0;i < numUVs;i++) { - for(size_t i = 0;i < numUVs;i++) - { - size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); - vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size(), - Ogre::HardwareBuffer::HBU_STATIC); + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), + srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); + vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); - const std::vector &uvlist = data->uvlist[i]; - - vbuf->writeData(0, elemSize*srcVerts.size(), &uvlist[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, - Ogre::VES_TEXTURE_COORDINATES, i); - bind->setBinding(nextBuf++, vbuf); - } + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + bind->setBinding(nextBuf++, vbuf); } // Triangle faces From 973fdeb2e01be028de7e5fa0b3df473c72fce397 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 15:21:28 -0700 Subject: [PATCH 222/817] Improve particle system placement when no emitters are specified --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index bf4621e6f..3c876283e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1566,7 +1566,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } if(!partsys->isAttached()) - entitybase->attachObjectToBone(partnode->name, partsys); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partnode->recIndex); + Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); + entitybase->attachObjectToBone(trgtbone->getName(), partsys); + } } catch(std::exception &e) { std::cerr<< "Particles exception: "< Date: Tue, 9 Apr 2013 01:24:17 +0200 Subject: [PATCH 223/817] Fix several NPCs spawning in the ground --- apps/openmw/mwworld/scene.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2244a4fc6..439f76131 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -118,6 +118,7 @@ namespace MWWorld float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; + // Load terrain physics first... if (cell->mCell->isExterior()) { ESM::Land* land = @@ -137,6 +138,7 @@ namespace MWWorld } } + // ... then references. This is important for adjustPosition to work correctly. /// \todo rescale depending on the state of a new GMST insertCell (*cell, true); @@ -439,7 +441,6 @@ namespace MWWorld insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics, rescale); - insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics, rescale); @@ -447,11 +448,13 @@ namespace MWWorld insertCellRefList(mRendering, cell.mLights, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics, rescale); - insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics, rescale); + // Load NPCs and creatures _after_ everything else (important for adjustPosition to work correctly) + insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale); } void Scene::addObjectToScene (const Ptr& ptr) From 623c2c8201c80857bbaefe4278b04e88cdda269b Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 07:45:07 +0200 Subject: [PATCH 224/817] Minor fix --- apps/openmw/mwworld/actionequip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 51d0de6fe..d5927b6c5 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,7 +43,7 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (*it).canBeEquipped (actor, *it)) + switch(MWWorld::Class::get (getTarget()).canBeEquipped (actor, getTarget())) { case 0: return; From ec6dff38b187691b809c4b90ac15c27a972d4da2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 11:40:36 +0200 Subject: [PATCH 225/817] added basic spell table --- apps/opencs/model/world/data.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadspel.cpp | 10 ++++++++++ components/esm/loadspel.hpp | 3 +++ 9 files changed, 55 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b385c5b4c..af2b17bd9 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -99,6 +99,13 @@ CSMWorld::Data::Data() mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); + mSpells.addColumn (new StringIdColumn); + mSpells.addColumn (new RecordStateColumn); + mSpells.addColumn (new NameColumn); + mSpells.addColumn (new FlagColumn ("Autocalc", 0x1)); + mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); + mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -109,6 +116,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); + addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); } CSMWorld::Data::~Data() @@ -217,6 +225,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() return mBirthsigns; } +const CSMWorld::IdCollection& CSMWorld::Data::getSpells() const +{ + return mSpells; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSpells() +{ + return mSpells; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -261,6 +279,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SCPT: mScripts.load (reader, base); break; case ESM::REC_REGN: mRegions.load (reader, base); break; case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; + case ESM::REC_SPEL: mSpells.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 122e855d8..d7b69ba5e 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -36,6 +37,7 @@ namespace CSMWorld IdCollection mScripts; IdCollection mRegions; IdCollection mBirthsigns; + IdCollection mSpells; std::vector mModels; std::map mModelIndex; @@ -92,6 +94,10 @@ namespace CSMWorld IdCollection& getBirthsigns(); + const IdCollection& getSpells() const; + + IdCollection& getSpells(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6d305d6c0..11f487788 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -27,6 +27,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -43,6 +44,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 0586719f1..5586b22e7 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -53,7 +53,9 @@ namespace CSMWorld Type_Regions, Type_Region, Type_Birthsigns, - Type_Birthsign + Type_Birthsign, + Type_Spells, + Type_Spell }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index af9b81420..dfdcb1036 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -121,6 +121,10 @@ void CSVDoc::View::setupWorldMenu() QAction *birthsigns = new QAction (tr ("Birthsigns"), this); connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView())); world->addAction (birthsigns); + + QAction *spells = new QAction (tr ("Spells"), this); + connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); + world->addAction (spells); } void CSVDoc::View::setupUi() @@ -316,6 +320,11 @@ void CSVDoc::View::addBirthsignsSubView() addSubView (CSMWorld::UniversalId::Type_Birthsigns); } +void CSVDoc::View::addSpellsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Spells); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 12944e569..9241efbb9 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -131,6 +131,8 @@ namespace CSVDoc void addRegionsSubView(); void addBirthsignsSubView(); + + void addSpellsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 23c66319c..c9ef4df8d 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -24,6 +24,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, + CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index b0f1ca64b..8149fe4ce 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -20,4 +20,14 @@ void Spell::save(ESMWriter &esm) mEffects.save(esm); } + void Spell::blank() + { + mData.mType = 0; + mData.mCost = 0; + mData.mFlags = 0; + + mName.clear(); + + mEffects.mList.clear(); + } } diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 0d5e0be52..3a620962d 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -43,6 +43,9 @@ struct Spell void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From ae0a7d5bcde2e15b228b388f9e693b1453378a36 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 11:53:47 +0200 Subject: [PATCH 226/817] added cost and type columns to spell table --- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 48 ++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 2 ++ apps/opencs/view/doc/viewmanager.cpp | 8 +++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 5c2ce8a67..23049164f 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -34,7 +34,8 @@ namespace CSMWorld Display_GlobalVarType, Display_Specialisation, Display_Attribute, - Display_Boolean + Display_Boolean, + Display_SpellType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fbc533779..6d6d1b1ef 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -675,6 +675,54 @@ namespace CSMWorld return true; } }; + + template + struct SpellTypeColumn : public Column + { + SpellTypeColumn() : Column ("Type", ColumnBase::Display_SpellType) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mType; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mType = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct CostColumn : public Column + { + CostColumn() : Column ("Cost", ColumnBase::Display_Integer) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mCost; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + record2.mData.mCost = data.toInt(); + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index af2b17bd9..84b49b6bc 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -102,6 +102,8 @@ CSMWorld::Data::Data() mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); mSpells.addColumn (new NameColumn); + mSpells.addColumn (new SpellTypeColumn); + mSpells.addColumn (new CostColumn); mSpells.addColumn (new FlagColumn ("Autocalc", 0x1)); mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 3be7228b3..050bd51fe 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -49,6 +49,11 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) "Luck", 0 }; + static const char *sSpellTypes[] = + { + "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0 + }; + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -62,6 +67,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, new CSVWorld::EnumDelegateFactory (sAttributes, true)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType, + new CSVWorld::EnumDelegateFactory (sSpellTypes)); } CSVDoc::ViewManager::~ViewManager() From 40bb772e34aedf01c472aad93147c3a81a5a983d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 12:44:49 +0200 Subject: [PATCH 227/817] added verifier for spell record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/spellcheck.cpp | 35 ++++++++++++++++++++++++++ apps/opencs/model/tools/spellcheck.hpp | 29 +++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/spellcheck.cpp create mode 100644 apps/opencs/model/tools/spellcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 87221d7af..76d4280c8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -36,7 +36,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck + birthsigncheck spellcheck ) diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp new file mode 100644 index 000000000..3adee0a4e --- /dev/null +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -0,0 +1,35 @@ + +#include "spellcheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SpellCheckStage::SpellCheckStage (const CSMWorld::IdCollection& spells) +: mSpells (spells) +{} + +int CSMTools::SpellCheckStage::setup() +{ + return mSpells.getSize(); +} + +void CSMTools::SpellCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Spell& spell = mSpells.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Spell, spell.mId); + + // test for empty name and description + if (spell.mName.empty()) + messages.push_back (id.toString() + "|" + spell.mId + " has an empty name"); + + // test for invalid cost values + if (spell.mData.mCost<0) + messages.push_back (id.toString() + "|" + spell.mId + " has a negative spell costs"); + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/spellcheck.hpp b/apps/opencs/model/tools/spellcheck.hpp new file mode 100644 index 000000000..056639219 --- /dev/null +++ b/apps/opencs/model/tools/spellcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SPELLCHECK_H +#define CSM_TOOLS_SPELLCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that spell records are internally consistent + class SpellCheckStage : public Stage + { + const CSMWorld::IdCollection& mSpells; + + public: + + SpellCheckStage (const CSMWorld::IdCollection& spells); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 78796de41..803861203 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -19,6 +19,7 @@ #include "soundcheck.hpp" #include "regioncheck.hpp" #include "birthsigncheck.hpp" +#include "spellcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -72,6 +73,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); + + mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); } return mVerifier; From be4a01bdb4edf99ca9618ea477f31f44366fc85e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 14:27:32 +0200 Subject: [PATCH 228/817] added missing recrod type columns --- apps/opencs/model/world/data.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 84b49b6bc..14aff47e8 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -33,11 +33,13 @@ CSMWorld::Data::Data() mGmsts.addColumn (new StringIdColumn); mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); + mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Skill)); mSkills.addColumn (new AttributeColumn); mSkills.addColumn (new SpecialisationColumn); for (int i=0; i<4; ++i) @@ -46,6 +48,7 @@ CSMWorld::Data::Data() mClasses.addColumn (new StringIdColumn); mClasses.addColumn (new RecordStateColumn); + mClasses.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Class)); mClasses.addColumn (new NameColumn); mClasses.addColumn (new AttributesColumn (0)); mClasses.addColumn (new AttributesColumn (1)); @@ -59,6 +62,7 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); + mFactions.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Faction)); mFactions.addColumn (new NameColumn); mFactions.addColumn (new AttributesColumn (0)); mFactions.addColumn (new AttributesColumn (1)); @@ -68,6 +72,7 @@ CSMWorld::Data::Data() mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); + mRaces.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Race)); mRaces.addColumn (new NameColumn); mRaces.addColumn (new DescriptionColumn); mRaces.addColumn (new FlagColumn ("Playable", 0x1)); @@ -79,6 +84,7 @@ CSMWorld::Data::Data() mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); + mSounds.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Sound)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); @@ -86,21 +92,25 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); + mScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Script)); mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); + mRegions.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Region)); mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); + mBirthsigns.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Birthsign)); mBirthsigns.addColumn (new NameColumn); mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); + mSpells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Spell)); mSpells.addColumn (new NameColumn); mSpells.addColumn (new SpellTypeColumn); mSpells.addColumn (new CostColumn); From cd33f40c8fb1497b3db6eae569a45a9c334cf9d4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 14:28:31 +0200 Subject: [PATCH 229/817] re-enabled opening of record subviews via double click in table --- apps/opencs/view/world/tablesubview.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index f4deceb49..bb4bb76c6 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -21,6 +21,5 @@ void CSVWorld::TableSubView::setEditLock (bool locked) void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) { - /// \todo re-enable, after dialogue sub views have been fixed up -// focusId (mTable->getUniversalId (index.row())); + focusId (mTable->getUniversalId (index.row())); } \ No newline at end of file From 46925e93a6f79402f0838eabab30f02c4352a828 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 16:14:08 +0200 Subject: [PATCH 230/817] Second minor fix --- apps/openmw/mwclass/armor.cpp | 3 +++ apps/openmw/mwworld/actionequip.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index ddab6f754..a14b2667e 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -343,6 +343,9 @@ namespace MWClass { MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if(weapon == invStore.end()) + return 1; + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index d5927b6c5..82431ac8f 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -18,6 +18,7 @@ namespace MWWorld void ActionEquip::executeImp (const Ptr& actor) { + MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); // slots that this item can be equipped in @@ -27,7 +28,7 @@ namespace MWWorld MWWorld::ContainerStoreIterator it = invStore.begin(); for (; it != invStore.end(); ++it) { - if (*it == getTarget()) + if (*it == object) { break; } @@ -43,7 +44,7 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (getTarget()).canBeEquipped (actor, getTarget())) + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) { case 0: return; @@ -70,10 +71,10 @@ namespace MWWorld } } - std::string script = MWWorld::Class::get(*it).getScript(*it); + std::string script = MWWorld::Class::get(object).getScript(object); /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") - (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); + (object).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); } } From 9f9d978b0f1020777403f2b5f2e67b7ed0a03cd7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 09:07:05 -0700 Subject: [PATCH 231/817] Use an enum to specify the NPC's view mode (normal, head only) --- apps/openmw/mwrender/characterpreview.cpp | 8 ++++---- apps/openmw/mwrender/npcanimation.cpp | 8 ++++---- apps/openmw/mwrender/npcanimation.hpp | 10 ++++++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 616543a7d..0da20f3da 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -59,8 +59,8 @@ namespace MWRender mNode = renderRoot->createChildSceneNode(); - mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), + 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); mNode->setVisible (false); @@ -101,8 +101,8 @@ namespace MWRender assert(mAnimation); delete mAnimation; - mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), + 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); float scale=1.f; MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d7620a8de..685edb68c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -56,7 +56,7 @@ NpcAnimation::~NpcAnimation() } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, ViewMode viewMode) : Animation(ptr), mStateID(-1), mTimeToChange(0), @@ -73,7 +73,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mGloveL(inv.end()), mGloveR(inv.end()), mSkirtIter(inv.end()), - mHeadOnly(headOnly) + mViewMode(viewMode) { mNpc = mPtr.get()->mBase; @@ -222,7 +222,7 @@ void NpcAnimation::updateParts(bool forceupdate) if(!forceupdate) return; - for(size_t i = 0;i < slotlistsize && !mHeadOnly;i++) + for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); @@ -259,7 +259,7 @@ void NpcAnimation::updateParts(bool forceupdate) if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); - if (mHeadOnly) + if(mViewMode == VM_HeadOnly) return; static const struct { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 224d174f4..44639e94a 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -26,6 +26,11 @@ struct PartInfo { const char name[32]; }; +enum ViewMode { + VM_Normal, + VM_HeadOnly +}; + private: static const size_t sPartListSize = 27; static const PartInfo sPartList[sPartListSize]; @@ -39,7 +44,7 @@ private: std::string mHeadModel; std::string mHairModel; std::string mBodyPrefix; - bool mHeadOnly; + ViewMode mViewMode; float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; @@ -73,7 +78,8 @@ private: public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly=false); + MWWorld::InventoryStore& inv, int visibilityFlags, + ViewMode viewMode=VM_Normal); virtual ~NpcAnimation(); virtual Ogre::Vector3 runAnimation(float timepassed); From 029d56572777fcccf01639166af528b63c2837e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 09:23:07 -0700 Subject: [PATCH 232/817] Avoid calling setVisible for character previews --- apps/openmw/mwrender/characterpreview.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 0da20f3da..8396acaea 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -62,8 +62,6 @@ namespace MWRender mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - mNode->setVisible (false); - Ogre::Vector3 scale = mNode->getScale(); mCamera->setPosition(mPosition * scale); mCamera->lookAt(mLookAt * scale); @@ -108,8 +106,6 @@ namespace MWRender MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); mNode->setScale(Ogre::Vector3(scale)); - mNode->setVisible (false); - mCamera->setPosition(mPosition * mNode->getScale()); mCamera->lookAt(mLookAt * mNode->getScale()); @@ -139,12 +135,8 @@ namespace MWRender mNode->setOrientation (Ogre::Quaternion::IDENTITY); - mNode->setVisible (true); - mRenderTarget->update(); mSelectionBuffer->update(); - - mNode->setVisible (false); } int InventoryPreview::getSlotSelected (int posX, int posY) @@ -178,9 +170,7 @@ namespace MWRender updateCamera(); - mNode->setVisible (true); mRenderTarget->update(); - mNode->setVisible (false); } void RaceSelectionPreview::setPrototype(const ESM::NPC &proto) From 44ef02eb99c2cf7f4cab6d60320e155fe5183579 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:04:59 +0200 Subject: [PATCH 233/817] Third minor fix --- apps/openmw/mwworld/actionequip.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 82431ac8f..2877a2c5a 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -40,19 +40,20 @@ namespace MWWorld bool equipped = false; + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + { + case 0: + return; //Item cannot be equipped, so function breaks. + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) - { - case 0: - return; - case 2: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - case 3: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) From 248fff6eb7323b7c7cf4f56afff53c1b820e6fb3 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:41:03 +0200 Subject: [PATCH 234/817] Fourth minor fix --- apps/openmw/mwworld/actionequip.cpp | 4 +++- apps/openmw/mwworld/inventorystore.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 2877a2c5a..39c5abe34 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,11 +43,13 @@ namespace MWWorld switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) { case 0: - return; //Item cannot be equipped, so function breaks. + return; case 2: invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; case 3: invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; } // equip the item in the first free slot diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 9f51db353..782e3f920 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -192,8 +192,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) continue; case 2: invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; case 3: invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; } if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped From bd93e63150dc69c0e3caf27231dfbede99772baf Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:46:27 +0200 Subject: [PATCH 235/817] Fifth minor fix --- apps/openmw/mwworld/actionequip.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 39c5abe34..fd35d0dd3 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -21,6 +21,18 @@ namespace MWWorld MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + { + case 0: + return; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; + } + // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(getTarget()).getEquipmentSlots(getTarget()); @@ -40,18 +52,6 @@ namespace MWWorld bool equipped = false; - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) - { - case 0: - return; - case 2: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - break; - case 3: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - break; - } - // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) From 6ca2b1af743b659e44b9601f99c985a92a66e99a Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Tue, 9 Apr 2013 19:24:41 +0100 Subject: [PATCH 236/817] fix for turning animations playing when in vanity mode --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 13 +++++++++++-- apps/openmw/mwrender/renderingmanager.cpp | 10 ++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 040dc703c..39e985890 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -319,6 +319,7 @@ namespace MWBase virtual void allowVanityMode(bool allow) = 0; virtual void togglePlayerLooking(bool enable) = 0; virtual void changeVanityModeScale(float factor) = 0; + virtual bool vanityRotateCamera(float * rot) = 0; virtual void renderPlayer() = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c23106be1..6a34161e0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -533,8 +533,17 @@ namespace MWInput float scale = MWBase::Environment::get().getFrameDuration(); if(scale <= 0.0f) scale = 1.0f; - mPlayer.setYaw(x/scale); - mPlayer.setPitch(-y/scale); + float rot[3]; + rot[0] = -y; + rot[1] = 0.0f; + rot[2] = x; + + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer.setYaw(x/scale); + mPlayer.setPitch(-y/scale); + } if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index cd5ab19b9..029cf394b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -891,6 +891,16 @@ void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float mPlayer->getSightAngles(pitch, yaw); } +bool RenderingManager::vanityRotateCamera(float* rot) +{ + if(!mPlayer->isVanityOrPreviewModeEnabled()) + return false; + + Ogre::Vector3 vRot(rot); + mPlayer->rotateCamera(vRot, true); + return true; +} + void RenderingManager::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) { return mLocalMap->getInteriorMapPosition (position, nX, nY, x, y); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b343a60bd..cece7a95f 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -88,6 +88,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList mPlayer->setCameraDistance(-factor/120.f*10, true, true); } + bool vanityRotateCamera(float* rot); + void getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw); void attachCameraTo(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ae9b7a06b..11ccd8f2f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1364,6 +1364,11 @@ namespace MWWorld return physactor && physactor->getOnGround(); } + bool World::vanityRotateCamera(float * rot) + { + return mRendering->vanityRotateCamera(rot); + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5ae87a1ff..7b12babee 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -361,6 +361,8 @@ namespace MWWorld mRendering->changeVanityModeScale(factor); } + virtual bool vanityRotateCamera(float * rot); + virtual void renderPlayer(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); From 0e7d555cdf5ebd475792ffe13c0ad7d653288267 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Apr 2013 20:31:00 +0200 Subject: [PATCH 237/817] Terrain material now uses multiple passes if required, which means it can support an arbitrary number of layers. Also re-enables PSSM. --- apps/openmw/mwgui/settingswindow.cpp | 4 +- apps/openmw/mwrender/shadows.cpp | 5 +- apps/openmw/mwrender/terrainmaterial.cpp | 161 ++++++++++++++++------- apps/openmw/mwrender/terrainmaterial.hpp | 3 + files/materials/shadowcaster.shader | 3 +- files/materials/terrain.shader | 33 ++++- 6 files changed, 148 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 58754472d..5fb6e5000 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -236,9 +236,7 @@ namespace MWGui mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); - //mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); - mShadowsLargeDistance->setCaptionWithReplacing("#{sOff}"); - mShadowsLargeDistance->setEnabled (false); + mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); mShadowsEnabledButton->setCaptionWithReplacing(Settings::Manager::getBool("enabled", "Shadows") ? "#{sOn}" : "#{sOff}"); mActorShadows->setCaptionWithReplacing(Settings::Manager::getBool("actor shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 595a82294..0d066a0ec 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -28,10 +28,7 @@ void Shadows::recreate() { bool enabled = Settings::Manager::getBool("enabled", "Shadows"); - // Split shadow maps are currently disabled because the terrain cannot cope with them - // (Too many texture units) Solution would be a multi-pass terrain material - //bool split = Settings::Manager::getBool("split", "Shadows"); - const bool split = false; + bool split = Settings::Manager::getBool("split", "Shadows"); sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false"); diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 8a568883d..dd74254be 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -68,59 +68,113 @@ namespace MWRender Ogre::MaterialManager::getSingleton().remove(matName); mMaterial = sh::Factory::getInstance().createMaterialInstance (matName); - mMaterial->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); - sh::MaterialInstancePass* p = mMaterial->createPass (); + int numPasses = getRequiredPasses(terrain); + int maxLayersInOnePass = getMaxLayersPerPass(terrain); - p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); - p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); - - p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap))); - - // global colour map - sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap"); - colourMap->setProperty ("texture_alias", sh::makeProperty (new sh::StringValue(mMaterial->getName() + "_colourMap"))); - colourMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - - // global normal map - sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap"); - normalMap->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getTerrainNormalMap ()->getName()))); - normalMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - - Ogre::uint maxLayers = getMaxLayers(terrain); - Ogre::uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount()); - Ogre::uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - - p->mShaderProperties.setProperty ("num_layers", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numLayers)))); - p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); - - // blend maps - for (Ogre::uint i = 0; i < numBlendTextures; ++i) + for (int pass=0; passcreateTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); - blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(i)))); - blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - } + int layerOffset = maxLayersInOnePass * pass; + int blendmapOffset = (pass == 0) ? 1 : 0; // the first layer of the first pass is the base layer and does not need a blend map - // layer maps - for (Ogre::uint i = 0; i < numLayers; ++i) - { - sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); - diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(i, 0)))); - p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), - sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(int((i-1) / 4)) + "." + getComponent(int((i-1) % 4))))); - } + sh::MaterialInstancePass* p = mMaterial->createPass (); - // shadow - for (Ogre::uint i = 0; i < 3; ++i) - { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); - } + p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); + p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); + if (pass != 0) + { + p->setProperty ("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); + // Only write if depth is equal to the depth value written by the previous pass. + p->setProperty ("depth_func", sh::makeProperty(new sh::StringValue("equal"))); + } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty(new sh::StringValue( - Ogre::StringConverter::toString(numBlendTextures + numLayers + 2)))); + p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap))); + p->mShaderProperties.setProperty ("is_first_pass", sh::makeProperty(new sh::BooleanValue(pass == 0))); + + // global colour map + sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap"); + colourMap->setProperty ("texture_alias", sh::makeProperty (new sh::StringValue(mMaterial->getName() + "_colourMap"))); + colourMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + // global normal map + sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap"); + normalMap->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getTerrainNormalMap ()->getName()))); + normalMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + Ogre::uint numLayersInThisPass = std::min(maxLayersInOnePass, terrain->getLayerCount()-layerOffset); + + // HACK: Terrain::getLayerBlendTextureIndex should be const, but it is not. + // Remove this once ogre got fixed. + Ogre::Terrain* nonconstTerrain = const_cast(terrain); + + // a blend map might be shared between two passes + // so we can't just use terrain->getBlendTextureCount() + Ogre::uint numBlendTextures=0; + std::vector blendTextures; + for (unsigned int layer=blendmapOffset; layergetBlendTextureName(nonconstTerrain->getLayerBlendTextureIndex( + static_cast(layerOffset+layer)).first); + if (std::find(blendTextures.begin(), blendTextures.end(), blendTextureName) == blendTextures.end()) + { + blendTextures.push_back(blendTextureName); + ++numBlendTextures; + } + } + + p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass)))); + p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); + + // blend maps + // the index of the first blend map used in this pass + int blendmapStart; + if (terrain->getLayerCount() == 1) // special case. if there's only one layer, we don't need blend maps at all + blendmapStart = 0; + else + blendmapStart = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+blendmapOffset)).first; + for (Ogre::uint i = 0; i < numBlendTextures; ++i) + { + sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); + blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(blendmapStart+i)))); + blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + } + + // layer maps + for (Ogre::uint i = 0; i < numLayersInThisPass; ++i) + { + sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); + diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(layerOffset+i, 0)))); + + if (i+layerOffset > 0) + { + int blendTextureIndex = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+i)).first; + int blendTextureComponent = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+i)).second; + p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), + sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(blendTextureIndex-blendmapStart) + "." + getComponent(blendTextureComponent)))); + } + else + { + // just to make it shut up about blendmap_component_0 not existing in the first pass. + // it might be retrieved, but will never survive the preprocessing step. + p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), + sh::makeProperty (new sh::StringValue(""))); + } + } + + // shadow + for (Ogre::uint i = 0; i < 3; ++i) + { + sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); + shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + } + + p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( + Ogre::StringConverter::toString(numBlendTextures + numLayersInThisPass + 2)))); + + // make sure the pass index is fed to the permutation handler, because blendmap components may be different + p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(pass))); + } return Ogre::MaterialManager::getSingleton().getByName(matName); } @@ -142,6 +196,11 @@ namespace MWRender } Ogre::uint8 TerrainMaterial::Profile::getMaxLayers(const Ogre::Terrain* terrain) const + { + return 255; + } + + int TerrainMaterial::Profile::getMaxLayersPerPass (const Ogre::Terrain* terrain) { // count the texture units free Ogre::uint8 freeTextureUnits = 16; @@ -151,11 +210,21 @@ namespace MWRender --freeTextureUnits; // shadow --freeTextureUnits; + --freeTextureUnits; + --freeTextureUnits; // each layer needs 1.25 units (1xdiffusespec, 0.25xblend) return static_cast(freeTextureUnits / (1.25f)); } + int TerrainMaterial::Profile::getRequiredPasses (const Ogre::Terrain* terrain) + { + int maxLayersPerPass = getMaxLayersPerPass(terrain); + assert(terrain->getLayerCount()); + assert(maxLayersPerPass); + return std::ceil(static_cast(terrain->getLayerCount()) / maxLayersPerPass); + } + void TerrainMaterial::Profile::updateParams(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain) { } diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index fe1214cf5..c90499bae 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -72,6 +72,9 @@ namespace MWRender private: sh::MaterialInstance* mMaterial; + int getRequiredPasses (const Ogre::Terrain* terrain); + int getMaxLayersPerPass (const Ogre::Terrain* terrain); + bool mGlobalColourMap; }; diff --git a/files/materials/shadowcaster.shader b/files/materials/shadowcaster.shader index b312d414c..b992366a7 100644 --- a/files/materials/shadowcaster.shader +++ b/files/materials/shadowcaster.shader @@ -45,8 +45,7 @@ // use alpha channel of the first texture float alpha = shSample(texture1, UV).a; - // discard if alpha is less than 0.5 - if (alpha < 1.0) + if (alpha < 0.5) discard; #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index c73b582f8..de90a6cf6 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -1,6 +1,6 @@ #include "core.h" -#define IS_FIRST_PASS 1 +#define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) #define FOG @shGlobalSettingBool(fog) @@ -23,6 +23,9 @@ #define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) +#if !IS_FIRST_PASS +// This is not the first pass. +#endif #if NEED_DEPTH @shAllocatePassthrough(1, depth) @@ -222,7 +225,11 @@ float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif - + +#if !IS_FIRST_PASS +float combinedAlpha = 0.f; +#endif + // Layer calculations @shForeach(@shPropertyString(num_blendmaps)) float4 blendValues@shIterator = shSample(blendMap@shIterator, UV); @@ -232,12 +239,20 @@ @shForeach(@shPropertyString(num_layers)) -#if IS_FIRST_PASS == 1 && @shIterator == 0 - // first layer of first pass doesn't need a blend map +#if IS_FIRST_PASS + #if @shIterator == 0 + // first layer of first pass is the base layer and doesn't need a blend map albedo = shSample(diffuseMap0, UV * 10).rgb; -#else + #else albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); - + #endif +#else + #if @shIterator == 0 + albedo = shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator); + #else + albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); + #endif + combinedAlpha += blendValues@shPropertyString(blendmap_component_@shIterator); #endif @shEndForeach @@ -325,6 +340,12 @@ // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); + +#if IS_FIRST_PASS + shOutputColour(0).a = 1; +#else + shOutputColour(0).a = min(combinedAlpha, 1.f); +#endif } #endif From a700c50e84e06586e3a766940e43f33e156d67ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 15:10:14 -0700 Subject: [PATCH 238/817] Add a first-person view mode to NpcAnimation And use it instead of showing/hiding the player. --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 64 ++++++++++++++++++++++----- apps/openmw/mwrender/npcanimation.hpp | 3 ++ apps/openmw/mwrender/player.cpp | 12 +++-- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 067e85672..a849b20ef 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -476,7 +476,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con Ogre::Vector3 Animation::runAnimation(float timepassed) { - Ogre::Vector3 movement = Ogre::Vector3::ZERO; + Ogre::Vector3 movement(0.0f); timepassed *= mAnimSpeedMult; while(mCurrentAnim && mPlaying) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 685edb68c..7e59f8f6c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -130,7 +130,40 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); setAnimationSources(skelnames); - updateParts(true); + forceUpdate(); +} + +void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) +{ + assert(viewMode != VM_HeadOnly); + mViewMode = viewMode; + + /* FIXME: Enable this once first-person animations work. */ +#if 0 + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mNpc->mRace); + + bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; + std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); + + std::vector skelnames(1, smodel); + if(!mNpc->isMale() && !isBeast) + skelnames.push_back("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + skelnames.push_back("meshes\\argonian_swimkna.nif"); + if(mNpc->mModel.length() > 0) + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + if(mViewMode == VM_FirstPerson) + { + smodel = (!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif"); + skelnames.push_back(smodel); + } + setAnimationSources(skelnames); +#endif + + for(size_t i = 0;i < sPartListSize;i++) + removeIndividualPart(i); + forceUpdate(); } void NpcAnimation::updateParts(bool forceupdate) @@ -254,13 +287,18 @@ void NpcAnimation::updateParts(bool forceupdate) reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio); } - if(mPartPriorities[ESM::PRT_Head] < 1) - addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); - if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) - addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); - + if(mViewMode != VM_FirstPerson) + { + if(mPartPriorities[ESM::PRT_Head] < 1) + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); + if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); + } if(mViewMode == VM_HeadOnly) return; + /* FIXME: Remove this once we figure out how to show what in first-person */ + if(mViewMode == VM_FirstPerson) + return; static const struct { ESM::PartReferenceType type; @@ -288,6 +326,7 @@ void NpcAnimation::updateParts(bool forceupdate) { ESM::PRT_Tail, { "tail", "" } } }; + const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) { @@ -298,14 +337,14 @@ void NpcAnimation::updateParts(bool forceupdate) if(!mNpc->isMale()) { - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]+ext); if(part == 0) - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]+ext); } if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]+ext); if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]+ext); if(part) addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); @@ -431,6 +470,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts) { + const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; for(std::size_t i = 0; i < parts.size(); i++) { const ESM::PartReference &part = parts[i]; @@ -440,9 +480,9 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorisMale()) - bodypart = partStore.search(part.mFemale); + bodypart = partStore.search(part.mFemale+ext); if(!bodypart) - bodypart = partStore.search(part.mMale); + bodypart = partStore.search(part.mMale+ext); if(bodypart) addOrReplaceIndividualPart(part.mPart, group, priority, "meshes\\"+bodypart->mModel); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 44639e94a..f2f4c6669 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -28,6 +28,7 @@ struct PartInfo { enum ViewMode { VM_Normal, + VM_FirstPerson, VM_HeadOnly }; @@ -84,6 +85,8 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); + void setViewMode(ViewMode viewMode); + void forceUpdate() { updateParts(true); } }; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 55fda326f..439264f3a 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -124,8 +124,6 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - /// \fixme We shouldn't hide the whole model, just certain components of the character (head, chest, feet, etc) - mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); if (mFirstPersonView && !mVanity.enabled) { return; } @@ -139,6 +137,8 @@ namespace MWRender void Player::toggleViewMode() { mFirstPersonView = !mFirstPersonView; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); if (mFirstPersonView) { mCamera->setPosition(0.f, 0.f, 0.f); setLowHeight(false); @@ -168,6 +168,9 @@ namespace MWRender mVanity.enabled = enable; mVanity.forced = force && enable; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + float offset = mPreviewCam.offset; Ogre::Vector3 rot(0.f, 0.f, 0.f); if (mVanity.enabled) { @@ -194,6 +197,8 @@ namespace MWRender return; } mPreviewMode = enable; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); float offset = mCamera->getPosition().z; if (mPreviewMode) { mMainCam.offset = offset; @@ -305,7 +310,8 @@ namespace MWRender delete mAnimation; mAnimation = anim; - mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); } void Player::setHeight(float height) From 50d8353a8db9bdeb5f577449e7ae784a3f15bd70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 16:51:04 -0700 Subject: [PATCH 239/817] Fix a hack so arms dont show in first-person --- apps/openmw/mwrender/npcanimation.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7e59f8f6c..96220f47d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -255,6 +255,14 @@ void NpcAnimation::updateParts(bool forceupdate) if(!forceupdate) return; + /* FIXME: Remove this once we figure out how to show what in first-person */ + if(mViewMode == VM_FirstPerson) + { + for(size_t i = 0;i < slotlistsize;i++) + this->*slotlist[i].part = inv.getSlot(slotlist[i].slot); + return; + } + for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); @@ -296,9 +304,6 @@ void NpcAnimation::updateParts(bool forceupdate) } if(mViewMode == VM_HeadOnly) return; - /* FIXME: Remove this once we figure out how to show what in first-person */ - if(mViewMode == VM_FirstPerson) - return; static const struct { ESM::PartReferenceType type; From ce9bc6d9bae9d03b8c614e781b420789eb9531d4 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 00:32:05 -0400 Subject: [PATCH 240/817] MwGui windowManager calls fixed to use MWBase::Environment::get().getWindowManager, filenames in MwGui now comply with naming conventions --- apps/openmw/mwgui/alchemywindow.cpp | 17 +- apps/openmw/mwgui/alchemywindow.hpp | 4 +- apps/openmw/mwgui/birth.cpp | 9 +- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 4 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.cpp | 2 +- apps/openmw/mwgui/class.cpp | 93 ++-- apps/openmw/mwgui/class.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 46 +- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/dialoguehistory.cpp | 76 +++ apps/openmw/mwgui/dialoguehistory.hpp | 19 + apps/openmw/mwgui/enchantingdialog.cpp | 42 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 20 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 8 +- apps/openmw/mwgui/loadingscreen.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 446 +++++++++++++++++ apps/openmw/mwgui/mapwindow.hpp | 107 ++++ apps/openmw/mwgui/merchantrepair.cpp | 10 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 5 +- apps/openmw/mwgui/messagebox.hpp | 8 +- apps/openmw/mwgui/quickkeysmenu.cpp | 20 +- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/race.cpp | 26 +- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 11 +- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 4 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 14 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 14 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 21 +- apps/openmw/mwgui/spellcreationdialog.hpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 18 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 580 ++++++++++++++++++++++ apps/openmw/mwgui/statswindow.hpp | 83 ++++ apps/openmw/mwgui/textinput.cpp | 70 +++ apps/openmw/mwgui/textinput.hpp | 33 ++ apps/openmw/mwgui/tooltips.cpp | 29 +- apps/openmw/mwgui/tooltips.hpp | 6 +- apps/openmw/mwgui/tradewindow.cpp | 24 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 18 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 18 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 14 +- apps/openmw/mwgui/waitdialog.hpp | 2 +- apps/openmw/mwgui/widgets.cpp | 39 +- apps/openmw/mwgui/widgets.hpp | 8 - apps/openmw/mwgui/windowbase.cpp | 54 ++ apps/openmw/mwgui/windowbase.hpp | 47 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 8 +- apps/openmw/mwgui/windowpinnablebase.cpp | 28 ++ apps/openmw/mwgui/windowpinnablebase.hpp | 28 ++ 72 files changed, 1863 insertions(+), 328 deletions(-) create mode 100644 apps/openmw/mwgui/dialoguehistory.cpp create mode 100644 apps/openmw/mwgui/dialoguehistory.hpp create mode 100644 apps/openmw/mwgui/mapwindow.cpp create mode 100644 apps/openmw/mwgui/mapwindow.hpp create mode 100644 apps/openmw/mwgui/statswindow.cpp create mode 100644 apps/openmw/mwgui/statswindow.hpp create mode 100644 apps/openmw/mwgui/textinput.cpp create mode 100644 apps/openmw/mwgui/textinput.hpp create mode 100644 apps/openmw/mwgui/windowbase.cpp create mode 100644 apps/openmw/mwgui/windowbase.hpp create mode 100644 apps/openmw/mwgui/windowpinnablebase.cpp create mode 100644 apps/openmw/mwgui/windowpinnablebase.hpp diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index ca7f1b913..1ae534797 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -64,8 +64,8 @@ namespace MWGui { mAlchemy.clear(); - mWindowManager.removeGuiMode(GM_Alchemy); - mWindowManager.removeGuiMode(GM_Inventory); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); } void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) @@ -77,40 +77,40 @@ namespace MWGui if (result == MWMechanics::Alchemy::Result_NoName) { - mWindowManager.messageBox("#{sNotifyMessage37}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage37}"); return; } // check if mortar & pestle is available (always needed) if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle) { - mWindowManager.messageBox("#{sNotifyMessage45}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage45}"); return; } // make sure 2 or more ingredients were selected if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients) { - mWindowManager.messageBox("#{sNotifyMessage6a}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage6a}"); return; } if (result == MWMechanics::Alchemy::Result_NoEffects) { - mWindowManager.messageBox("#{sNotifyMessage8}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); return; } if (result == MWMechanics::Alchemy::Result_Success) { - mWindowManager.messageBox("#{sPotionSuccess}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sPotionSuccess}"); MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f); } else if (result == MWMechanics::Alchemy::Result_RandomFailure) { // potion failed - mWindowManager.messageBox("#{sNotifyMessage8}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); } @@ -232,7 +232,6 @@ namespace MWGui MyGUI::IntCoord coord(0, 0, mEffectsBox->getWidth(), 24); Widgets::MWEffectListPtr effectsWidget = mEffectsBox->createWidget ("MW_StatName", coord, MyGUI::Align::Left | MyGUI::Align::Top); - effectsWidget->setWindowManager(&mWindowManager); Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list); effectsWidget->setEffectList(_list); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 5f84e73e9..933975f0c 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,7 +5,7 @@ #include "../mwmechanics/alchemy.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "container.hpp" #include "widgets.hpp" @@ -38,7 +38,7 @@ namespace MWGui virtual void onReferenceUnavailable() { ; } void update(); - + private: MWMechanics::Alchemy mAlchemy; diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 4b07dd698..d899ab00b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -46,7 +46,7 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); updateBirths(); @@ -59,9 +59,9 @@ void BirthDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void BirthDialog::open() @@ -221,7 +221,7 @@ void BirthDialog::updateSpells() if (!categories[category].spells.empty()) { MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); - label->setCaption(mWindowManager.getGameSettingString(categories[category].label, "")); + label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); mSpellItems.push_back(label); coord.top += lineHeight; @@ -230,7 +230,6 @@ void BirthDialog::updateSpells() { const std::string &spellId = *it; spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); - spellWidget->setWindowManager(&mWindowManager); spellWidget->setSpellId(spellId); mSpellItems.push_back(spellWidget); diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index d3f82dace..033501f22 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_BIRTH_H #define MWGUI_BIRTH_H -#include "window_base.hpp" +#include "windowbase.hpp" /* This file contains the dialog for choosing a birth sign. diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 777751069..d57953d07 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -102,7 +102,7 @@ void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) // no 3d sounds because the object could be in a container. MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - mWindowManager.removeGuiMode(GM_Book); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) @@ -112,7 +112,7 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) MWWorld::ActionTake take(mBook); take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - mWindowManager.removeGuiMode(GM_Book); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index a509f131f..c2a9dca89 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_BOOKWINDOW_H #define MWGUI_BOOKWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index bcf3c335d..27de7cee9 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -1,6 +1,6 @@ #include "charactercreation.hpp" -#include "text_input.hpp" +#include "textinput.hpp" #include "race.hpp" #include "class.hpp" #include "birth.hpp" diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index a2f09096a..8c352d508 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -26,7 +26,7 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW // Centre dialog center(); - setText("ReflectT", mWindowManager.getGameSettingString("sMessageQuestionAnswer1", "")); + setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); getWidget(mClassImage, "ClassImage"); getWidget(mClassName, "ClassName"); @@ -37,7 +37,7 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); } @@ -77,16 +77,12 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); - mFavoriteAttribute[0]->setWindowManager(&mWindowManager); - mFavoriteAttribute[1]->setWindowManager(&mWindowManager); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - mMajorSkill[i]->setWindowManager(&mWindowManager); - mMinorSkill[i]->setWindowManager(&mWindowManager); } getWidget(mClassList, "ClassList"); @@ -115,9 +111,9 @@ void PickClassDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void PickClassDialog::open() @@ -224,7 +220,7 @@ void PickClassDialog::updateStats() "sSpecializationMagic", "sSpecializationStealth" }; - std::string specName = mWindowManager.getGameSettingString(specIds[specialization], specIds[specialization]); + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); mSpecializationName->setCaption(specName); ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); @@ -365,10 +361,10 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) { setText(""); ButtonList buttons; - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu1", "")); - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu2", "")); - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu3", "")); - buttons.push_back(mWindowManager.getGameSettingString("sBack", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); setButtons(buttons); } @@ -384,20 +380,18 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("SpecializationT", mWindowManager.getGameSettingString("sChooseClassMenu1", "Specialization")); + setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); getWidget(mSpecializationName, "SpecializationName"); mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); - setText("FavoriteAttributesT", mWindowManager.getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); + setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); - mFavoriteAttribute0->setWindowManager(&mWindowManager); - mFavoriteAttribute1->setWindowManager(&mWindowManager); mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - setText("MajorSkillT", mWindowManager.getGameSettingString("sSkillClassMajor", "")); - setText("MinorSkillT", mWindowManager.getGameSettingString("sSkillClassMinor", "")); + setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); + setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; @@ -410,11 +404,10 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) std::vector::const_iterator end = mSkills.end(); for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) { - (*it)->setWindowManager(&mWindowManager); (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); } - setText("LabelT", mWindowManager.getGameSettingString("sName", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); getWidget(mEditName, "EditName"); // Make sure the edit box has focus @@ -522,32 +515,32 @@ void CreateClassDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } // widget controls void CreateClassDialog::onDialogCancel() { - mWindowManager.removeDialog(mSpecDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); mSpecDialog = 0; - mWindowManager.removeDialog(mAttribDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); mAttribDialog = 0; - mWindowManager.removeDialog(mSkillDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); mSkillDialog = 0; - mWindowManager.removeDialog(mDescDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); mDescDialog = 0; } void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) { delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(mWindowManager); + mSpecDialog = new SelectSpecializationDialog(*MWBase::Environment::get().getWindowManager()); mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); mSpecDialog->setVisible(true); @@ -558,7 +551,7 @@ void CreateClassDialog::onSpecializationSelected() mSpecializationId = mSpecDialog->getSpecializationId(); setSpecialization(mSpecializationId); - mWindowManager.removeDialog(mSpecDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); mSpecDialog = 0; } @@ -570,7 +563,7 @@ void CreateClassDialog::setSpecialization(int id) "sSpecializationMagic", "sSpecializationStealth" }; - std::string specName = mWindowManager.getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); mSpecializationName->setCaption(specName); ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); } @@ -578,7 +571,7 @@ void CreateClassDialog::setSpecialization(int id) void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(mWindowManager); + mAttribDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager()); mAffectedAttribute = _sender; mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); @@ -599,7 +592,7 @@ void CreateClassDialog::onAttributeSelected() mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); } mAffectedAttribute->setAttributeId(id); - mWindowManager.removeDialog(mAttribDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); mAttribDialog = 0; update(); @@ -608,7 +601,7 @@ void CreateClassDialog::onAttributeSelected() void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(mWindowManager); + mSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager()); mAffectedSkill = _sender; mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); @@ -633,14 +626,14 @@ void CreateClassDialog::onSkillSelected() } mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); - mWindowManager.removeDialog(mSkillDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); mSkillDialog = 0; update(); } void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) { - mDescDialog = new DescriptionDialog(mWindowManager); + mDescDialog = new DescriptionDialog(*MWBase::Environment::get().getWindowManager()); mDescDialog->setTextInput(mDescription); mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); mDescDialog->setVisible(true); @@ -649,7 +642,7 @@ void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) { mDescription = mDescDialog->getTextInput(); - mWindowManager.removeDialog(mDescDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); mDescDialog = 0; } @@ -673,14 +666,14 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sSpecializationMenu1", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); getWidget(mSpecialization0, "Specialization0"); getWidget(mSpecialization1, "Specialization1"); getWidget(mSpecialization2, "Specialization2"); - std::string combat = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); - std::string magic = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); - std::string stealth = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); + std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); + std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); mSpecialization0->setCaption(combat); mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); @@ -696,7 +689,7 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); } @@ -733,7 +726,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sAttributesMenu1", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); for (int i = 0; i < 8; ++i) { @@ -741,7 +734,6 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan char theIndex = '0'+i; getWidget(attribute, std::string("Attribute").append(1, theIndex)); - attribute->setWindowManager(&parWindowManager); attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); @@ -749,7 +741,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); } @@ -780,10 +772,10 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sSkillsMenu1", "")); - setText("CombatLabelT", mWindowManager.getGameSettingString("sSpecializationCombat", "")); - setText("MagicLabelT", mWindowManager.getGameSettingString("sSpecializationMagic", "")); - setText("StealthLabelT", mWindowManager.getGameSettingString("sSpecializationStealth", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); + setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); + setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); + setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); for(int i = 0; i < 9; i++) { @@ -833,7 +825,6 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) { for (int i = 0; i < 9; ++i) { - mSkills[spec][i].widget->setWindowManager(&mWindowManager); mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); @@ -842,7 +833,7 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); } @@ -876,7 +867,7 @@ DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); - okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 8c60331d8..11da1a791 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -3,7 +3,7 @@ #include "widgets.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" /* This file contains the dialogs for choosing a class. diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 45941f2ad..a925cad55 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_CONFIRMATIONDIALOG_H #define MWGUI_CONFIRMATIONDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 7e6a0b088..f7846e70e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -751,7 +751,7 @@ void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) /// \todo I don't think this is the correct flag to check if (MWWorld::Class::get(mPtr).isEssential(mPtr)) - mWindowManager.messageBox("#{sDisposeCorpseFail}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); else MWBase::Environment::get().getWorld()->deleteObject(mPtr); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 03bd519f7..7a3e804e5 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -3,7 +3,7 @@ #include "../mwworld/esmstore.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "../mwclass/container.hpp" diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 80da6eea0..d5155839d 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_COUNTDIALOG_H #define MWGUI_COUNTDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b3aa27617..0939da1b1 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -18,7 +18,7 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" -#include "dialogue_history.hpp" +#include "dialoguehistory.hpp" #include "widgets.hpp" #include "list.hpp" #include "tradewindow.hpp" @@ -89,17 +89,17 @@ void PersuasionDialog::onPersuade(MyGUI::Widget *sender) else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; else if (sender == mBribe10Button) { - mWindowManager.getTradeWindow()->addOrRemoveGold(-10); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); type = MWBase::MechanicsManager::PT_Bribe10; } else if (sender == mBribe100Button) { - mWindowManager.getTradeWindow()->addOrRemoveGold(-100); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); type = MWBase::MechanicsManager::PT_Bribe100; } else /*if (sender == mBribe1000Button)*/ { - mWindowManager.getTradeWindow()->addOrRemoveGold(-1000); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); type = MWBase::MechanicsManager::PT_Bribe1000; } @@ -113,7 +113,7 @@ void PersuasionDialog::open() WindowModal::open(); center(); - int playerGold = mWindowManager.getInventoryWindow()->getPlayerGold(); + int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); mBribe10Button->setEnabled (playerGold >= 10); mBribe100Button->setEnabled (playerGold >= 100); @@ -251,45 +251,45 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) } else if (topic == gmst.find("sCompanionShare")->getString()) { - mWindowManager.pushGuiMode(GM_Companion); - mWindowManager.showCompanionWindow(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); + MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); } else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) { - mWindowManager.pushGuiMode(GM_Barter); - mWindowManager.getTradeWindow()->startTrade(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); } else if (topic == gmst.find("sSpells")->getString()) { - mWindowManager.pushGuiMode(GM_SpellBuying); - mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); } else if (topic == gmst.find("sTravel")->getString()) { - mWindowManager.pushGuiMode(GM_Travel); - mWindowManager.getTravelWindow()->startTravel(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); } else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) { - mWindowManager.pushGuiMode(GM_SpellCreation); - mWindowManager.startSpellMaking (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); } else if (topic == gmst.find("sEnchanting")->getString()) { - mWindowManager.pushGuiMode(GM_Enchanting); - mWindowManager.startEnchanting (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); + MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); } else if (topic == gmst.find("sServiceTrainingTitle")->getString()) { - mWindowManager.pushGuiMode(GM_Training); - mWindowManager.startTraining (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->startTraining (mPtr); } else if (topic == gmst.find("sRepair")->getString()) { - mWindowManager.pushGuiMode(GM_MerchantRepair); - mWindowManager.startRepair (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->startRepair (mPtr); } } } @@ -456,7 +456,7 @@ std::string DialogueWindow::parseText(const std::string& text) } else { - if( !mWindowManager.getTranslationDataStorage().hasTranslation() ) + if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) { @@ -528,7 +528,7 @@ void DialogueWindow::goodbye() void DialogueWindow::onReferenceUnavailable() { - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void DialogueWindow::onFrame() diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 187731fc7..e78856c95 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_DIALOGE_H #define MWGUI_DIALOGE_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include diff --git a/apps/openmw/mwgui/dialoguehistory.cpp b/apps/openmw/mwgui/dialoguehistory.cpp new file mode 100644 index 000000000..a122a7891 --- /dev/null +++ b/apps/openmw/mwgui/dialoguehistory.cpp @@ -0,0 +1,76 @@ +#include "dialoguehistory.hpp" + +#include "../mwbase/windowmanager.hpp" + +#include "widgets.hpp" + +#include "../mwworld/esmstore.hpp" + +#include +#include + +#include +#include + +using namespace MWGui; +using namespace Widgets; + +MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) +{ + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::TextIterator iterator(getCaption()); + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if (pos < _pos) + continue; + else if (pos == _pos) + break; + } + return colour; +} + +MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) +{ + bool breakOnNext = false; + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::UString colour2 = colour; + MyGUI::TextIterator iterator(getCaption()); + MyGUI::TextIterator col_start = iterator; + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if(colour != colour2) + { + if(breakOnNext) + { + return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + } + col_start = iterator; + colour2 = colour; + } + if (pos < _pos) + continue; + else if (pos == _pos) + { + breakOnNext = true; + } + } + return ""; +} + +void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) +{ + MyGUI::UString head("\n#D8C09A"); + head.append(parText); + head.append("#B29154\n"); + addText(head); +} + +void DialogueHistory::addDialogText(const MyGUI::UString& parText) +{ + addText(parText); + addText("\n"); +} diff --git a/apps/openmw/mwgui/dialoguehistory.hpp b/apps/openmw/mwgui/dialoguehistory.hpp new file mode 100644 index 000000000..c37504af7 --- /dev/null +++ b/apps/openmw/mwgui/dialoguehistory.hpp @@ -0,0 +1,19 @@ +#ifndef MWGUI_DIALOGE_HISTORY_H +#define MWGUI_DIALOGE_HISTORY_H +#include + +namespace MWGui +{ + class DialogueHistory : public MyGUI::EditBox + { + MYGUI_RTTI_DERIVED( DialogueHistory ) + public: + Widget* getClient() { return mClient; } + MyGUI::UString getColorAtPos(size_t _pos); + MyGUI::UString getColorTextAt(size_t _pos); + void addDialogHeading(const MyGUI::UString& parText); + void addDialogText(const MyGUI::UString& parText); + }; +} +#endif + diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 276e7a904..02d847d1a 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -69,19 +69,19 @@ namespace MWGui switch(mEnchanting.getEnchantType()) { case 0: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastOnce","Cast Once")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); mAddEffectDialog.constantEffect=false; break; case 1: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenStrikes", "When Strikes")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); mAddEffectDialog.constantEffect=false; break; case 2: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenUsed", "When Used")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); mAddEffectDialog.constantEffect=false; break; case 3: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastConstant", "Cast Constant")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); mAddEffectDialog.constantEffect=true; break; } @@ -126,20 +126,20 @@ namespace MWGui void EnchantingDialog::onReferenceUnavailable () { - mWindowManager.removeGuiMode (GM_Dialogue); - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } void EnchantingDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}", - ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, mWindowManager); + ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); @@ -190,7 +190,7 @@ namespace MWGui if(mEnchanting.getGemCharge()==0) { - mWindowManager.messageBox ("#{sNotifyMessage32}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage32}"); return; } @@ -227,14 +227,14 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}", - ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, mWindowManager); + ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mItemSelectionDialog->drawItems (); - //mWindowManager.messageBox("#{sInventorySelectNoSoul}"); + //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); } void EnchantingDialog::notifyEffectsChanged () @@ -254,50 +254,50 @@ namespace MWGui { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}"); return; } if (mName->getCaption ().empty()) { - mWindowManager.messageBox ("#{sNotifyMessage10}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; } if (mEnchanting.soulEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage52}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage52}"); return; } if (mEnchanting.itemEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage11}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage11}"); return; } if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue()) { - mWindowManager.messageBox ("#{sNotifyMessage29}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}"); return; } mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - if (mEnchanting.getEnchantPrice() > mWindowManager.getInventoryWindow()->getPlayerGold()) + if (mEnchanting.getEnchantPrice() > MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; } int result = mEnchanting.create(); if(result==1) - mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu12}"); else - mWindowManager.messageBox ("#{sNotifyMessage34}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage34}"); - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index a7861c422..822199ac6 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_ENCHANTINGDIALOG_H #define MWGUI_ENCHANTINGDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "spellcreationdialog.hpp" diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index aab9e62a4..c65566ce3 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -1,4 +1,4 @@ -#include "map_window.hpp" +#include "mapwindow.hpp" #include diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 001f42bd1..393f03a54 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -130,7 +130,7 @@ namespace MWGui void InventoryWindow::onPinToggled() { - mWindowManager.setWeaponVisibility(!mPinned); + MWBase::Environment::get().getWindowManager()->setWeaponVisibility(!mPinned); } void InventoryWindow::onAvatarClicked(MyGUI::Widget* _sender) @@ -162,13 +162,13 @@ namespace MWGui // the "Take" button should not be visible. // NOTE: the take button is "reset" when the window opens, so we can safely do the following // without screwing up future book windows - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - mWindowManager.setDragDrop(false); + MWBase::Environment::get().getWindowManager()->setDragDrop(false); drawItems(); @@ -224,11 +224,11 @@ namespace MWGui { invStore.equip(slot, invStore.end()); std::string script = MWWorld::Class::get(*it).getScript(*it); - + // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared if(script != "") (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 0); - + return; } } @@ -285,16 +285,16 @@ namespace MWGui void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory - if (mWindowManager.getSpellWindow()) - mWindowManager.getSpellWindow()->updateSpells(); + if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) + MWBase::Environment::get().getWindowManager()->getSpellWindow()->updateSpells(); // update selected weapon icon MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if (weaponSlot == invStore.end()) - mWindowManager.unsetSelectedWeapon(); + MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon(); else - mWindowManager.setSelectedWeapon(*weaponSlot); /// \todo track weapon durability + MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*weaponSlot); /// \todo track weapon durability mPreviewDirty = true; diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fceb7ecef..61ee17ef9 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -4,7 +4,7 @@ #include "../mwrender/characterpreview.hpp" #include "container.hpp" -#include "window_pinnable_base.hpp" +#include "windowpinnablebase.hpp" #include "widgets.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cd1ff7ebb..73a2dca2e 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -6,7 +6,7 @@ #include #include -#include "window_base.hpp" +#include "windowbase.hpp" #include "imagebutton.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 67620d49d..dcecdccc1 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -183,7 +183,7 @@ namespace MWGui creatureStats.setLevel (creatureStats.getLevel()+1); pcStats.levelUp (); - mWindowManager.removeGuiMode (GM_Levelup); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Levelup); } } diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index 3c8b74800..a54948e2a 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_LEVELUPDIALOG_H #define MWGUI_LEVELUPDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 86f196d9f..306670512 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -195,12 +195,12 @@ namespace MWGui { changeWallpaper(); - mWindowManager.pushGuiMode(GM_LoadingWallpaper); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_LoadingWallpaper); } else { mBackgroundImage->setImageTexture(""); - mWindowManager.pushGuiMode(GM_Loading); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Loading); } } @@ -211,8 +211,8 @@ namespace MWGui mLoadingOn = false; mFirstLoad = false; - mWindowManager.removeGuiMode(GM_Loading); - mWindowManager.removeGuiMode(GM_LoadingWallpaper); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_LoadingWallpaper); } void LoadingScreen::changeWallpaper () diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 176fc0f5d..cb33975ae 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -4,7 +4,7 @@ #include #include -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp new file mode 100644 index 000000000..029974d2b --- /dev/null +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -0,0 +1,446 @@ +#include "mapwindow.hpp" + +#include + +#include +#include +#include + +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" + +#include "../mwrender/globalmap.hpp" + +#include "widgets.hpp" + +using namespace MWGui; + +LocalMapBase::LocalMapBase() + : mCurX(0) + , mCurY(0) + , mInterior(false) + , mFogOfWar(true) + , mLocalMap(NULL) + , mMapDragAndDrop(false) + , mPrefix() + , mChanged(true) + , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) + , mCompass(NULL) +{ +} + +void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) +{ + mLocalMap = widget; + mLayout = layout; + mMapDragAndDrop = mapDragAndDrop; + mCompass = compass; + + // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each + const int widgetSize = 512; + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", + MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); + + MyGUI::ImageBox* fog = map->createWidget("ImageBox", + MyGUI::IntCoord(0, 0, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); + + if (!mMapDragAndDrop) + { + map->setNeedMouseFocus(false); + fog->setNeedMouseFocus(false); + } + + mMapWidgets.push_back(map); + mFogWidgets.push_back(fog); + } + } +} + +void LocalMapBase::setCellPrefix(const std::string& prefix) +{ + mPrefix = prefix; + mChanged = true; +} + +void LocalMapBase::toggleFogOfWar() +{ + mFogOfWar = !mFogOfWar; + applyFogOfWar(); +} + +void LocalMapBase::applyFogOfWar() +{ + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" + + boost::lexical_cast(mCurY + (-1*(my-1))); + MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; + fog->setImageTexture(mFogOfWar ? + ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" + : "black.png" ) + : ""); + } + } + notifyMapChanged (); +} + +void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) +{ + applyFogOfWar (); +} + +void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) +{ + applyFogOfWar (); +} + +void LocalMapBase::setActiveCell(const int x, const int y, bool interior) +{ + if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell + + // clear all previous markers + for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) + { + if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + { + MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); + } + } + + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + // map + std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + + boost::lexical_cast(y + (-1*(my-1))); + + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; + + if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) + box->setImageTexture(image); + else + box->setImageTexture("black.png"); + + + // door markers + + // interior map only consists of one cell, so handle the markers only once + if (interior && (mx != 2 || my != 2)) + continue; + + MWWorld::CellStore* cell; + if (interior) + cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); + else + cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); + + std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); + + for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + { + MWBase::World::DoorMarker marker = *it; + + // convert world coordinates to normalized cell coordinates + MyGUI::IntCoord widgetCoord; + float nX,nY; + int cellDx, cellDy; + if (!interior) + { + const int cellSize = 8192; + + nX = (marker.x - cellSize * (x+mx-1)) / cellSize; + nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + } + else + { + Ogre::Vector2 position (marker.x, marker.y); + MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + } + + static int counter = 0; + ++counter; + MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); + markerWidget->setUserString("IsMarker", "true"); + markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); + markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); + + MarkerPosition markerPos; + markerPos.interior = interior; + markerPos.cellX = interior ? cellDx : x + mx - 1; + markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); + markerPos.nX = nX; + markerPos.nY = nY; + + markerWidget->setUserData(markerPos); + } + + + } + } + mInterior = interior; + mCurX = x; + mCurY = y; + mChanged = false; + + // fog of war + applyFogOfWar(); + + // set the compass texture again, because MyGUI determines sorting of ImageBox widgets + // based on the last setImageTexture call + std::string tex = "textures\\compass.dds"; + mCompass->setImageTexture(""); + mCompass->setImageTexture(tex); +} + + +void LocalMapBase::setPlayerPos(const float x, const float y) +{ + if (x == mLastPositionX && y == mLastPositionY) + return; + + notifyPlayerUpdate (); + + MyGUI::IntSize size = mLocalMap->getCanvasSize(); + MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); + MyGUI::IntCoord viewsize = mLocalMap->getCoord(); + MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + mLocalMap->setViewOffset(pos); + + mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); + mLastPositionX = x; + mLastPositionY = y; +} + +void LocalMapBase::setPlayerDir(const float x, const float y) +{ + if (x == mLastDirectionX && y == mLastDirectionY) + return; + + notifyPlayerUpdate (); + + MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(x,y); + rotatingSubskin->setAngle(angle); + + mLastDirectionX = x; + mLastDirectionY = y; +} + +// ------------------------------------------------------------------------------------------ + +MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) + , mGlobal(false) +{ + setCoord(500,0,320,300); + + mGlobalMapRender = new MWRender::GlobalMap(cacheDir); + mGlobalMapRender->render(); + + getWidget(mLocalMap, "LocalMap"); + getWidget(mGlobalMap, "GlobalMap"); + getWidget(mGlobalMapImage, "GlobalMapImage"); + getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); + getWidget(mPlayerArrowLocal, "CompassLocal"); + getWidget(mPlayerArrowGlobal, "CompassGlobal"); + + mGlobalMapImage->setImageTexture("GlobalMap.png"); + mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + + mGlobalMap->setVisible (false); + + getWidget(mButton, "WorldButton"); + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing("#{sWorld}"); + + getWidget(mEventBoxGlobal, "EventBoxGlobal"); + mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + getWidget(mEventBoxLocal, "EventBoxLocal"); + mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); +} + +MapWindow::~MapWindow() +{ + delete mGlobalMapRender; +} + +void MapWindow::setCellName(const std::string& cellName) +{ + setTitle("#{sCell=" + cellName + "}"); +} + +void MapWindow::addVisitedLocation(const std::string& name, int x, int y) +{ + float worldX, worldY; + mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); + + MyGUI::IntCoord widgetCoord( + worldX * mGlobalMapRender->getWidth()+6, + worldY * mGlobalMapRender->getHeight()+6, + 12, 12); + + + static int _counter=0; + MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + ++_counter; + + markerWidget = mEventBoxGlobal->createWidget("", + widgetCoord, MyGUI::Align::Default); + markerWidget->setNeedMouseFocus (true); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); +} + +void MapWindow::cellExplored(int x, int y) +{ + mGlobalMapRender->exploreCell(x,y); +} + +void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) +{ + if (_id!=MyGUI::MouseButton::Left) return; + mLastDragPos = MyGUI::IntPoint(_left, _top); +} + +void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) +{ + if (_id!=MyGUI::MouseButton::Left) return; + + MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; + + if (!mGlobal) + mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + else + mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); + + + mLastDragPos = MyGUI::IntPoint(_left, _top); +} + +void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) +{ + mGlobal = !mGlobal; + mGlobalMap->setVisible(mGlobal); + mLocalMap->setVisible(!mGlobal); + + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + + if (mGlobal) + globalMapUpdatePlayer (); +} + +void MapWindow::onPinToggled() +{ + MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); +} + +void MapWindow::open() +{ + mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + + for (unsigned int i=0; igetChildCount (); ++i) + { + if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") + mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + } + + globalMapUpdatePlayer(); + + mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); +} + +void MapWindow::globalMapUpdatePlayer () +{ + Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); + Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); + + float worldX, worldY; + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); + worldX *= mGlobalMapRender->getWidth(); + worldY *= mGlobalMapRender->getHeight(); + + + // for interiors, we have no choice other than using the last position & direction. + /// \todo save this last position in the savegame? + if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + { + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + + MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(dir.x, dir.y); + rotatingSubskin->setAngle(angle); + + // set the view offset so that player is in the center + MyGUI::IntSize viewsize = mGlobalMap->getSize(); + MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); + mGlobalMap->setViewOffset(viewoffs); + } +} + +void MapWindow::notifyPlayerUpdate () +{ + globalMapUpdatePlayer (); +} + +void MapWindow::notifyMapChanged () +{ + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); +} diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp new file mode 100644 index 000000000..329854e18 --- /dev/null +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -0,0 +1,107 @@ +#ifndef MWGUI_MAPWINDOW_H +#define MWGUI_MAPWINDOW_H + +#include "windowpinnablebase.hpp" + +namespace MWRender +{ + class GlobalMap; +} + +namespace MWGui +{ + class LocalMapBase + { + public: + LocalMapBase(); + void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false); + + void setCellPrefix(const std::string& prefix); + void setActiveCell(const int x, const int y, bool interior=false); + void setPlayerDir(const float x, const float y); + void setPlayerPos(const float x, const float y); + + void toggleFogOfWar(); + + struct MarkerPosition + { + bool interior; + int cellX; + int cellY; + float nX; + float nY; + }; + + protected: + int mCurX, mCurY; + bool mInterior; + MyGUI::ScrollView* mLocalMap; + MyGUI::ImageBox* mCompass; + std::string mPrefix; + bool mChanged; + bool mFogOfWar; + + std::vector mMapWidgets; + std::vector mFogWidgets; + + void applyFogOfWar(); + + void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); + void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); + + virtual void notifyPlayerUpdate() {} + virtual void notifyMapChanged() {} + + OEngine::GUI::Layout* mLayout; + + bool mMapDragAndDrop; + + float mLastPositionX; + float mLastPositionY; + float mLastDirectionX; + float mLastDirectionY; + }; + + class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase + { + public: + MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); + virtual ~MapWindow(); + + void setCellName(const std::string& cellName); + + void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map + void cellExplored(int x, int y); + + virtual void open(); + + private: + void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onWorldButtonClicked(MyGUI::Widget* _sender); + + void globalMapUpdatePlayer(); + + MyGUI::ScrollView* mGlobalMap; + MyGUI::ImageBox* mGlobalMapImage; + MyGUI::ImageBox* mGlobalMapOverlay; + MyGUI::ImageBox* mPlayerArrowLocal; + MyGUI::ImageBox* mPlayerArrowGlobal; + MyGUI::Button* mButton; + MyGUI::IntPoint mLastDragPos; + bool mGlobal; + + MyGUI::Button* mEventBoxGlobal; + MyGUI::Button* mEventBoxLocal; + + MWRender::GlobalMap* mGlobalMapRender; + + protected: + virtual void onPinToggled(); + + virtual void notifyPlayerUpdate(); + virtual void notifyMapChanged(); + + }; +} +#endif diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 1c9056748..f24d2d417 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -72,7 +72,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) MyGUI::Button* button = mList->createWidget( - (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + (price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, currentY, 0, @@ -82,7 +82,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; - button->setEnabled(price<=mWindowManager.getInventoryWindow()->getPlayerGold()); + button->setEnabled(price<=MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()); button->setUserString("Price", boost::lexical_cast(price)); button->setUserData(*iter); button->setCaptionWithReplacing(name); @@ -95,7 +95,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY))); mGoldLabel->setCaptionWithReplacing("#{sGold}: " - + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); } void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) @@ -120,14 +120,14 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); int price = boost::lexical_cast(sender->getUserString("Price")); - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); startRepair(mActor); } void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 4b7e2b8fb..2cd6c486a 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWGUI_MERCHANTREPAIR_H #define OPENMW_MWGUI_MERCHANTREPAIR_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 46663b67a..58bbc3c3a 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -7,9 +7,8 @@ using namespace MWGui; -MessageBoxManager::MessageBoxManager (MWBase::WindowManager *windowManager) +MessageBoxManager::MessageBoxManager (MWBase::WindowManager* windowManager) { - mWindowManager = windowManager; // defines mMessageBoxSpeed = 0.1; mInterMessageBoxe = NULL; @@ -371,7 +370,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan void InteractiveMessageBox::enterPressed() { - + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 859e1806a..c64953b66 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -3,7 +3,7 @@ #include -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwbase/windowmanager.hpp" @@ -40,7 +40,7 @@ namespace MWGui void removeMessageBox (float time, MessageBox *msgbox); bool removeMessageBox (MessageBox *msgbox); void setMessageBoxSpeed (int speed); - + void enterPressed(); int readPressedButton (); @@ -51,8 +51,6 @@ namespace MWGui void onButtonPressed(int button) { eventButtonPressed(button); eventButtonPressed.clear(); } - MWBase::WindowManager *mWindowManager; - private: std::vector mMessageBoxes; InteractiveMessageBox* mInterMessageBoxe; @@ -92,7 +90,7 @@ namespace MWGui private: void buttonActivated (MyGUI::Widget* _widget); - + MessageBoxManager& mMessageBoxManager; MyGUI::EditBox* mMessageWidget; MyGUI::Widget* mButtonsWidget; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 2e4bf9100..82835a805 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -109,14 +109,14 @@ namespace MWGui { // open assign dialog if (!mAssignDialog) - mAssignDialog = new QuickKeysMenuAssign(mWindowManager, this); + mAssignDialog = new QuickKeysMenuAssign(*MWBase::Environment::get().getWindowManager(), this); mAssignDialog->setVisible (true); } } void QuickKeysMenu::onOkButtonClicked (MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_QuickKeysMenu); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_QuickKeysMenu); } @@ -124,7 +124,7 @@ namespace MWGui { if (!mItemSelectionDialog ) { - mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, mWindowManager); + mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItem); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } @@ -139,7 +139,7 @@ namespace MWGui { if (!mMagicSelectionDialog ) { - mMagicSelectionDialog = new MagicSelectionDialog(mWindowManager, this); + mMagicSelectionDialog = new MagicSelectionDialog(*MWBase::Environment::get().getWindowManager(), this); } mMagicSelectionDialog->setVisible(true); @@ -281,7 +281,7 @@ namespace MWGui std::string spellId = button->getChildAt(0)->getUserString("Spell"); spells.setSelectedSpell(spellId); store.setSelectedEnchantItem(store.end()); - mWindowManager.setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); } else if (type == Type_Item) { @@ -303,11 +303,11 @@ namespace MWGui // the "Take" button should not be visible. // NOTE: the take button is "reset" when the window opens, so we can safely do the following // without screwing up future book windows - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } else if (type == Type_MagicItem) { @@ -341,12 +341,12 @@ namespace MWGui action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item); + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 345ffa0c8..d5b6e6cd8 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -4,7 +4,7 @@ #include "../mwworld/ptr.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index be693eb2b..167ad573a 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -74,7 +74,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("AppearanceT", mWindowManager.getGameSettingString("sRaceMenu1", "Appearance")); + setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); getWidget(mPreviewImage, "PreviewImage"); getWidget(mHeadRotate, "HeadRotate"); @@ -86,34 +86,34 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) // Set up next/previous buttons MyGUI::Button *prevButton, *nextButton; - setText("GenderChoiceT", mWindowManager.getGameSettingString("sRaceMenu2", "Change Sex")); + setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); getWidget(prevButton, "PrevGenderButton"); getWidget(nextButton, "NextGenderButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); - setText("FaceChoiceT", mWindowManager.getGameSettingString("sRaceMenu3", "Change Face")); + setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); getWidget(prevButton, "PrevFaceButton"); getWidget(nextButton, "NextFaceButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); - setText("HairChoiceT", mWindowManager.getGameSettingString("sRaceMenu4", "Change Hair")); + setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); getWidget(prevButton, "PrevHairButton"); getWidget(nextButton, "NextHairButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu5", "Race")); + setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); getWidget(mRaceList, "RaceList"); mRaceList->setScrollVisible(true); mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - setText("SkillsT", mWindowManager.getGameSettingString("sBonusSkillTitle", "Skill Bonus")); + setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); getWidget(mSkillList, "SkillList"); - setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials")); + setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); getWidget(mSpellPowerList, "SpellPowerList"); MyGUI::Button* backButton; @@ -122,7 +122,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); updateRaces(); @@ -136,9 +136,9 @@ void RaceDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void RaceDialog::open() @@ -156,7 +156,7 @@ void RaceDialog::open() const ESM::NPC proto = mPreview->getPrototype(); setRaceId(proto.mRace); recountParts(); - + std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); mFaceIndex = boost::lexical_cast(index) - 1; @@ -361,7 +361,7 @@ void RaceDialog::updateRaces() const MWWorld::Store &races = MWBase::Environment::get().getWorld()->getStore().get(); - + int index = 0; MWWorld::Store::iterator it = races.begin(); for (; it != races.end(); ++it) @@ -403,7 +403,6 @@ void RaceDialog::updateSkills() skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, std::string("Skill") + boost::lexical_cast(i)); - skillWidget->setWindowManager(&mWindowManager); skillWidget->setSkillNumber(skillId); skillWidget->setSkillValue(MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); ToolTips::createSkillToolTip(skillWidget, skillId); @@ -439,7 +438,6 @@ void RaceDialog::updateSpellPowers() { const std::string &spellpower = *it; spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); - spellPowerWidget->setWindowManager(&mWindowManager); spellPowerWidget->setSpellId(spellpower); spellPowerWidget->setUserString("ToolTipType", "Spell"); spellPowerWidget->setUserString("Spell", spellpower); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 0ca440ad5..4a4acd011 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -8,7 +8,7 @@ #include "../mwrender/characterpreview.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index f53ddc430..43c262ad8 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -133,7 +133,7 @@ void Repair::updateRepairView() void Repair::onCancel(MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_Repair); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } void Repair::onRepairItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index c14b1955b..824e0b6d2 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWGUI_REPAIR_H #define OPENMW_MWGUI_REPAIR_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" #include "../mwmechanics/repair.hpp" diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 50508cc5f..74b189345 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -53,15 +53,15 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) // Setup dynamic stats getWidget(mHealth, "Health"); - mHealth->setTitle(mWindowManager.getGameSettingString("sHealth", "")); + mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); mHealth->setValue(45, 45); getWidget(mMagicka, "Magicka"); - mMagicka->setTitle(mWindowManager.getGameSettingString("sMagic", "")); + mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); mMagicka->setValue(50, 50); getWidget(mFatigue, "Fatigue"); - mFatigue->setTitle(mWindowManager.getGameSettingString("sFatigue", "")); + mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); mFatigue->setValue(160, 160); // Setup attributes @@ -71,7 +71,6 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) { getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); - attribute->setWindowManager(&mWindowManager); attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); attribute->setAttributeValue(MWAttribute::AttributeValue(0, 0)); } @@ -277,7 +276,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId addSeparator(coord1, coord2); } - addGroup(mWindowManager.getGameSettingString(titleId, titleDefault), coord1, coord2); + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); SkillList::const_iterator end = skills.end(); for (SkillList::const_iterator it = skills.begin(); it != end; ++it) @@ -296,7 +295,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId state = "increased"; else if (modified < base) state = "decreased"; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); for (int i=0; i<2; ++i) { diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 4f41ec42d..9775a52de 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_REVIEW_H #define MWGUI_REVIEW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwmechanics/stat.hpp" #include "widgets.hpp" diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 3bd3a4743..22884bfe6 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -66,7 +66,7 @@ void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - mWindowManager.removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) @@ -76,5 +76,5 @@ void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mScroll); take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - mWindowManager.removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 42b6395a9..59b39cab3 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SCROLLWINDOW_H #define MWGUI_SCROLLWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "imagebutton.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 58754472d..e21d4f589 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -274,7 +274,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_Settings); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -282,7 +282,7 @@ namespace MWGui if (index == MyGUI::ITEM_NONE) return; - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sNotifyMessage67}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); @@ -329,8 +329,8 @@ namespace MWGui void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) { - std::string on = mWindowManager.getGameSettingString("sOn", "On"); - std::string off = mWindowManager.getGameSettingString("sOff", "On"); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); + std::string off = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOff", "On"); bool newState; if (_sender->castType()->getCaption() == on) { @@ -437,8 +437,8 @@ namespace MWGui void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) { - std::string on = mWindowManager.getGameSettingString("sOn", "On"); - std::string off = mWindowManager.getGameSettingString("sOff", "On"); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); + std::string off = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOff", "On"); std::string val = static_cast(_sender)->getCaption(); if (val == off) @@ -610,7 +610,7 @@ namespace MWGui void SettingsWindow::onResetDefaultBindings(MyGUI::Widget* _sender) { - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sNotifyMessage66}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindingsAccept); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index fc1ec9e36..292c1233d 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SETTINGS_H #define MWGUI_SETTINGS_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index d39ad6a5a..9aa8074a2 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -48,7 +48,7 @@ namespace MWGui MyGUI::Button* toAdd = mSpellsView->createWidget( - (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + (price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, @@ -120,13 +120,13 @@ namespace MWGui { int price = *_sender->getUserData(); - if (mWindowManager.getInventoryWindow()->getPlayerGold()>=price) + if (MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()>=price) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); spells.add (mSpellsWidgetMap.find(_sender)->second); - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); startSpellBuying(mPtr); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); @@ -135,12 +135,12 @@ namespace MWGui void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); } void SpellBuyingWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, @@ -150,8 +150,8 @@ namespace MWGui void SpellBuyingWindow::onReferenceUnavailable() { // remove both Spells and Dialogue (since you always trade with the NPC/creature that you have previously talked to) - mWindowManager.removeGuiMode(GM_SpellBuying); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void SpellBuyingWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index f9cda35df..1418a9db5 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SpellBuyingWINDOW_H #define MWGUI_SpellBuyingWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" namespace MyGUI diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 592063a76..6fef91457 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -303,38 +303,38 @@ namespace MWGui void SpellCreationDialog::onCancelButtonClicked (MyGUI::Widget* sender) { - mWindowManager.removeGuiMode (MWGui::GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); } void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender) { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}"); return; } if (mNameEdit->getCaption () == "") { - mWindowManager.messageBox ("#{sNotifyMessage10}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; } if (mMagickaCost->getCaption() == "0") { - mWindowManager.messageBox ("#{sEnchantmentMenu8}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu8}"); return; } - if (boost::lexical_cast(mPriceLabel->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) + if (boost::lexical_cast(mPriceLabel->getCaption()) > MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; } mSpell.mName = mNameEdit->getCaption(); - mWindowManager.getTradeWindow()->addOrRemoveGold(-boost::lexical_cast(mPriceLabel->getCaption())); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-boost::lexical_cast(mPriceLabel->getCaption())); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); @@ -347,7 +347,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); - mWindowManager.removeGuiMode (GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } void SpellCreationDialog::open() @@ -357,8 +357,8 @@ namespace MWGui void SpellCreationDialog::onReferenceUnavailable () { - mWindowManager.removeGuiMode (GM_Dialogue); - mWindowManager.removeGuiMode (GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } void SpellCreationDialog::notifyEffectsChanged () @@ -601,7 +601,6 @@ namespace MWGui Widgets::MWSpellEffectPtr effect = button->createWidget("MW_EffectImage", MyGUI::IntCoord(0,0,0,24), MyGUI::Align::Default); effect->setNeedMouseFocus (false); - effect->setWindowManager (MWBase::Environment::get().getWindowManager ()); effect->setSpellEffect (params); effect->setSize(effect->getRequestedWidth (), 24); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 8f1c07180..facbdf530 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SPELLCREATION_H #define MWGUI_SPELLCREATION_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "list.hpp" #include "widgets.hpp" diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 021a849a0..257fab89d 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -71,7 +71,7 @@ namespace MWGui void SpellWindow::onPinToggled() { - mWindowManager.setSpellVisibility(!mPinned); + MWBase::Environment::get().getWindowManager()->setSpellVisibility(!mPinned); } void SpellWindow::open() @@ -140,7 +140,7 @@ namespace MWGui { store.setSelectedEnchantItem(store.end()); spells.setSelectedSpell(""); - mWindowManager.unsetSelectedSpell(); + MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); selectedItem = MWWorld::Ptr(); } } @@ -377,12 +377,12 @@ namespace MWGui action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item); + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); updateSpells(); } @@ -404,14 +404,14 @@ namespace MWGui if (spell->mData.mFlags & ESM::Spell::F_Always || spell->mData.mType == ESM::Spell::ST_Power) { - mWindowManager.messageBox("#{sDeleteSpellError}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); } else { // ask for confirmation mSpellToDelete = spellId; - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); - std::string question = mWindowManager.getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); question = boost::str(boost::format(question) % spell->mName); dialog->open(question); dialog->eventOkClicked.clear(); @@ -423,7 +423,7 @@ namespace MWGui { spells.setSelectedSpell(spellId); store.setSelectedEnchantItem(store.end()); - mWindowManager.setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); } updateSpells(); @@ -454,7 +454,7 @@ namespace MWGui if (spells.getSelectedSpell() == mSpellToDelete) { spells.setSelectedSpell(""); - mWindowManager.unsetSelectedSpell(); + MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); } spells.remove(mSpellToDelete); diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 1963d4346..b0994c590 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SPELLWINDOW_H #define MWGUI_SPELLWINDOW_H -#include "window_pinnable_base.hpp" +#include "windowpinnablebase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp new file mode 100644 index 000000000..0e0676c2f --- /dev/null +++ b/apps/openmw/mwgui/statswindow.cpp @@ -0,0 +1,580 @@ +#include "statswindow.hpp" + +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "tooltips.hpp" + + +using namespace MWGui; +const int StatsWindow::sLineHeight = 18; + +StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) + : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) + , mSkillView(NULL) + , mClientHeight(0) + , mMajorSkills() + , mMinorSkills() + , mMiscSkills() + , mSkillValues() + , mSkillWidgetMap() + , mFactionWidgetMap() + , mFactions() + , mBirthSignId() + , mReputation(0) + , mBounty(0) + , mSkillWidgets() + , mChanged(true) +{ + setCoord(0,0,498, 342); + + const char *names[][2] = + { + { "Attrib1", "sAttributeStrength" }, + { "Attrib2", "sAttributeIntelligence" }, + { "Attrib3", "sAttributeWillpower" }, + { "Attrib4", "sAttributeAgility" }, + { "Attrib5", "sAttributeSpeed" }, + { "Attrib6", "sAttributeEndurance" }, + { "Attrib7", "sAttributePersonality" }, + { "Attrib8", "sAttributeLuck" }, + { 0, 0 } + }; + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for (int i=0; names[i][0]; ++i) + { + setText (names[i][0], store.get().find (names[i][1])->getString()); + } + + getWidget(mSkillView, "SkillView"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); + + for (int i = 0; i < ESM::Skill::Length; ++i) + { + mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); + } + + MyGUI::WindowPtr t = static_cast(mMainWidget); + t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); +} + +void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); +} + +void StatsWindow::onWindowResize(MyGUI::Window* window) +{ + mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); + mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); +} + +void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) +{ + MyGUI::ProgressPtr pt; + getWidget(pt, name); + pt->setProgressRange(max); + pt->setProgressPosition(val); + + std::stringstream out; + out << val << "/" << max; + setText(tname, out.str().c_str()); +} + +void StatsWindow::setPlayerName(const std::string& playerName) +{ + static_cast(mMainWidget)->setCaption(playerName); + adjustWindowCaption(); +} + +void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) +{ + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + if (ids[i]==id) + { + std::ostringstream valueString; + valueString << value.getModified(); + setText (id, valueString.str()); + + MyGUI::TextBox* box; + getWidget(box, id); + + if (value.getModified()>value.getBase()) + box->_setWidgetState("increased"); + else if (value.getModified()_setWidgetState("decreased"); + else + box->_setWidgetState("normal"); + + break; + } +} + +void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) +{ + static const char *ids[] = + { + "HBar", "MBar", "FBar", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) + { + std::string id (ids[i]); + setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); + + // health, magicka, fatigue tooltip + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + if (i==0) + { + getWidget(w, "Health"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + else if (i==1) + { + getWidget(w, "Magicka"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + else if (i==2) + { + getWidget(w, "Fatigue"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } + } + } +} + +void StatsWindow::setValue (const std::string& id, const std::string& value) +{ + if (id=="name") + setPlayerName (value); + else if (id=="race") + setText ("RaceText", value); + else if (id=="class") + setText ("ClassText", value); +} + +void StatsWindow::setValue (const std::string& id, int value) +{ + if (id=="level") + { + std::ostringstream text; + text << value; + setText("LevelText", text.str()); + } +} + +void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) +{ + mSkillValues[parSkill] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + + widget->setCaption(text); + widget->_setWidgetState(state); + } +} + +void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) +{ + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } + + updateSkillArea(); +} + +void StatsWindow::onFrame () +{ + if (!mMainWidget->getVisible()) + return; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + + // level progress + MyGUI::Widget* levelWidget; + for (int i=0; i<2; ++i) + { + getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); + levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); + levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + } + + setFactions(PCstats.getFactionRanks()); + setExpelled(PCstats.getExpelled ()); + + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + + setBirthSign(signId); + setReputation (PCstats.getReputation ()); + setBounty (PCstats.getBounty ()); + + if (mChanged) + updateSkillArea(); +} + +void StatsWindow::setFactions (const FactionList& factions) +{ + if (mFactions != factions) + { + mFactions = factions; + mChanged = true; + } +} + +void StatsWindow::setExpelled (const std::set& expelled) +{ + if (mExpelled != expelled) + { + mExpelled = expelled; + mChanged = true; + } +} + +void StatsWindow::setBirthSign (const std::string& signId) +{ + if (signId != mBirthSignId) + { + mBirthSignId = signId; + mChanged = true; + } +} + +void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", + MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); +} + +void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", + MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + groupWidget->setCaption(label); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; +} + +MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::TextBox *skillNameWidget, *skillValueWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; +} + +MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillNameWidget; +} + +void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + int progressPercent = (modified - float(static_cast(modified))) * 100; + + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Skill* skill = esmStore.get().find(skillId); + assert(skill); + + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + const ESM::Attribute* attr = + esmStore.get().find(skill->mData.mAttribute); + assert(attr); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), + boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + } + + mSkillWidgetMap[skillId] = widget; + } +} + +void StatsWindow::updateSkillArea() +{ + mChanged = false; + + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); + mClientHeight = 0; + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::NPC *player = + world->getPlayer().getPlayer().get()->mBase; + + // race tooltip + const ESM::Race* playerRace = store.get().find(player->mRace); + + MyGUI::Widget* raceWidget; + getWidget(raceWidget, "RaceText"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + getWidget(raceWidget, "Race_str"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + + // class tooltip + MyGUI::Widget* classWidget; + + const ESM::Class *playerClass = + store.get().find(player->mClass); + + getWidget(classWidget, "ClassText"); + ToolTips::createClassToolTip(classWidget, *playerClass); + getWidget(classWidget, "Class_str"); + ToolTips::createClassToolTip(classWidget, *playerClass); + + if (!mFactions.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + std::set& expelled = PCstats.getExpelled (); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); + FactionList::const_iterator end = mFactions.end(); + for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + { + const ESM::Faction *faction = + store.get().find(it->first); + MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); + + std::string text; + + text += std::string("#DDC79E") + faction->mName; + + if (expelled.find(it->first) != expelled.end()) + text += "\n#{sExpelled}"; + else + { + text += std::string("\n#BF9959") + faction->mRanks[it->second]; + + if (it->second < 9) + { + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + + ESM::RankData rankData = faction->mData.mRankData[it->second+1]; + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.mSkill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + if (rankData.mSkill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); + } + } + + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "TextToolTip"); + w->setUserString("Caption_Text", text); + } + } + + if (!mBirthSignId.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); + const ESM::BirthSign *sign = + store.get().find(mBirthSignId); + MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); + + ToolTips::createBirthsignToolTip(w, mBirthSignId); + } + + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), + boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); + } + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), + boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); + } + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); +} + +void StatsWindow::onPinToggled() +{ + MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); +} diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp new file mode 100644 index 000000000..93e26e063 --- /dev/null +++ b/apps/openmw/mwgui/statswindow.hpp @@ -0,0 +1,83 @@ +#ifndef MWGUI_STATS_WINDOW_H +#define MWGUI_STATS_WINDOW_H + +#include "../mwworld/esmstore.hpp" + +#include +#include +#include +#include + +#include "../mwmechanics/stat.hpp" +#include "windowpinnablebase.hpp" + +namespace MWGui +{ + class WindowManager; + + class StatsWindow : public WindowPinnableBase + { + public: + typedef std::map FactionList; + + typedef std::vector SkillList; + + StatsWindow(MWBase::WindowManager& parWindowManager); + + /// automatically updates all the data in the stats window, but only if it has changed. + void onFrame(); + + void setBar(const std::string& name, const std::string& tname, int val, int max); + void setPlayerName(const std::string& playerName); + + /// Set value for the given ID. + void setValue (const std::string& id, const MWMechanics::Stat& value); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setValue (const std::string& id, const std::string& value); + void setValue (const std::string& id, int value); + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); + + void configureSkills (const SkillList& major, const SkillList& minor); + void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } + void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } + void updateSkillArea(); + + private: + void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + + void setFactions (const FactionList& factions); + void setExpelled (const std::set& expelled); + void setBirthSign (const std::string &signId); + + void onWindowResize(MyGUI::Window* window); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + + static const int sLineHeight; + + MyGUI::Widget* mLeftPane; + MyGUI::Widget* mRightPane; + + MyGUI::ScrollView* mSkillView; + int mLastPos, mClientHeight; + + SkillList mMajorSkills, mMinorSkills, mMiscSkills; + std::map > mSkillValues; + std::map mSkillWidgetMap; + std::map mFactionWidgetMap; + FactionList mFactions; ///< Stores a list of factions and the current rank + std::string mBirthSignId; + int mReputation, mBounty; + std::vector mSkillWidgets; //< Skills and other information + std::set mExpelled; + + bool mChanged; + + protected: + virtual void onPinToggled(); + }; +} +#endif diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp new file mode 100644 index 000000000..071971bef --- /dev/null +++ b/apps/openmw/mwgui/textinput.cpp @@ -0,0 +1,70 @@ +#include "textinput.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +using namespace MWGui; + +TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) + : WindowModal("openmw_text_input.layout", parWindowManager) +{ + // Centre dialog + center(); + + getWidget(mTextEdit, "TextEdit"); + mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); +} + +void TextInputDialog::setNextButtonShow(bool shown) +{ + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); +} + +void TextInputDialog::setTextLabel(const std::string &label) +{ + setText("LabelT", label); +} + +void TextInputDialog::open() +{ + WindowModal::open(); + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); +} + +// widget controls + +void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) +{ + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); +} + +void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) +{ + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); +} diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp new file mode 100644 index 000000000..6b371bae7 --- /dev/null +++ b/apps/openmw/mwgui/textinput.hpp @@ -0,0 +1,33 @@ +#ifndef MWGUI_TEXT_INPUT_H +#define MWGUI_TEXT_INPUT_H + +#include "windowbase.hpp" + +namespace MWGui +{ + class WindowManager; +} + +namespace MWGui +{ + class TextInputDialog : public WindowModal + { + public: + TextInputDialog(MWBase::WindowManager& parWindowManager); + + std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } + void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } + + void setNextButtonShow(bool shown); + void setTextLabel(const std::string &label); + virtual void open(); + + protected: + void onOkClicked(MyGUI::Widget* _sender); + void onTextAccepted(MyGUI::Edit* _sender); + + private: + MyGUI::EditBox* mTextEdit; + }; +} +#endif diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9292e60e5..7730019e8 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -12,7 +12,7 @@ #include "../mwworld/class.hpp" -#include "map_window.hpp" +#include "mapwindow.hpp" #include "widgets.hpp" #include "inventorywindow.hpp" @@ -22,7 +22,6 @@ using namespace MyGUI; ToolTips::ToolTips(MWBase::WindowManager* windowManager) : Layout("openmw_tooltips.layout") , mGameMode(true) - , mWindowManager(windowManager) , mFullHelp(false) , mEnabled(true) , mFocusToolTipX(0.0) @@ -81,9 +80,9 @@ void ToolTips::onFrame(float frameDuration) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Console) - || (mWindowManager->getMode() == GM_Container) - || (mWindowManager->getMode() == GM_Inventory))) + if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); @@ -93,7 +92,7 @@ void ToolTips::onFrame(float frameDuration) const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); IntSize tooltipSize; - if ((!objectclass.hasToolTip(mFocusObject))&&(mWindowManager->getMode() == GM_Console)) + if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) { setCoord(0, 0, 300, 300); mDynamicToolTipBox->setVisible(true); @@ -139,7 +138,7 @@ void ToolTips::onFrame(float frameDuration) mLastMouseX = mousePos.left; mLastMouseY = mousePos.top; - + if (mRemainingDelay > 0) return; @@ -167,8 +166,8 @@ void ToolTips::onFrame(float frameDuration) { return; } - - + + // special handling for markers on the local map: the tooltip should only be visible // if the marker is not hidden due to the fog of war. if (focus->getUserString ("IsMarker") == "true") @@ -190,11 +189,11 @@ void ToolTips::onFrame(float frameDuration) } else if (type == "AvatarItemSelection") { - MyGUI::IntCoord avatarPos = mWindowManager->getInventoryWindow ()->getAvatarScreenCoord (); + MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); - MWWorld::Ptr item = mWindowManager->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); mFocusObject = item; if (!mFocusObject.isEmpty ()) @@ -346,7 +345,7 @@ void ToolTips::findImageExtension(std::string& image) } IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) -{ +{ mDynamicToolTipBox->setVisible(true); std::string caption = info.caption; @@ -380,7 +379,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) setCoord(0, 0, 300, 300); const IntPoint padding(8, 8); - + const int maximumWidth = 500; const int imageCaptionHPadding = (caption != "" ? 8 : 0); @@ -424,7 +423,6 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEffectsWidget"); - effectsWidget->setWindowManager(mWindowManager); effectsWidget->setEffectList(info.effects); std::vector effectItems; @@ -444,7 +442,6 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); - enchantWidget->setWindowManager(mWindowManager); enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); std::vector enchantEffectItems; @@ -493,7 +490,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) (captionHeight-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); - + //if its too long we do hscroll with the caption if (captionSize.width > maximumWidth) { diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index da5a35221..e4fcb310c 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -82,8 +82,6 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - MWBase::WindowManager* mWindowManager; - MWWorld::Ptr mFocusObject; void findImageExtension(std::string& image); @@ -96,9 +94,9 @@ namespace MWGui float mFocusToolTipX; float mFocusToolTipY; - + int mHorizontalScrollIndex; - + float mDelay; float mRemainingDelay; // remaining time until tooltip will show diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 81a29e69b..718e6378b 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -85,7 +85,7 @@ namespace MWGui mCurrentBalance = 0; mCurrentMerchantOffer = 0; - mWindowManager.getInventoryWindow()->startTrade(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->startTrade(); mBoughtItems.clear(); @@ -127,7 +127,7 @@ namespace MWGui { bool goldFound = false; MWWorld::Ptr gold; - MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore(); + MWWorld::ContainerStore& playerStore = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getContainerStore(); for (MWWorld::ContainerStoreIterator it = playerStore.begin(); it != playerStore.end(); ++it) @@ -172,7 +172,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); // were there any items traded at all? - MWWorld::ContainerStore& playerBought = mWindowManager.getInventoryWindow()->getBoughtItems(); + MWWorld::ContainerStore& playerBought = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getBoughtItems(); MWWorld::ContainerStore& merchantBought = getBoughtItems(); if (playerBought.begin() == playerBought.end() && merchantBought.begin() == merchantBought.end()) { @@ -183,7 +183,7 @@ namespace MWGui } // check if the player can afford this - if (mCurrentBalance < 0 && mWindowManager.getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) + if (mCurrentBalance < 0 && MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) { // user notification MWBase::Environment::get().getWindowManager()-> @@ -258,7 +258,7 @@ namespace MWGui // success! make the item transfer. transferBoughtItems(); - mWindowManager.getInventoryWindow()->transferBoughtItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->transferBoughtItems(); // add or remove gold from the player. if (mCurrentBalance != 0) @@ -267,17 +267,17 @@ namespace MWGui std::string sound = "Item Gold Up"; MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - mWindowManager.removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { // i give you back your stuff! - returnBoughtItems(mWindowManager.getInventoryWindow()->getContainerStore()); + returnBoughtItems(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getContainerStore()); // now gimme back my stuff! - mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); - mWindowManager.removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) @@ -321,7 +321,7 @@ namespace MWGui void TradeWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); if (mCurrentBalance > 0) { @@ -422,8 +422,8 @@ namespace MWGui void TradeWindow::onReferenceUnavailable() { // remove both Trade and Dialogue (since you always trade with the NPC/creature that you have previously talked to) - mWindowManager.removeGuiMode(GM_Barter); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } int TradeWindow::getMerchantGold() diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 2e05d03d5..111c0935f 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -2,7 +2,7 @@ #define MWGUI_TRADEWINDOW_H #include "container.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 601b44d6c..c2b543a4f 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,7 @@ namespace MWGui { mPtr = actor; - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(actor).getNpcStats (actor); @@ -82,7 +82,7 @@ namespace MWGui int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer (mPtr,pcStats.getSkill (bestSkills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); - std::string skin = (price > mWindowManager.getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton"; + std::string skin = (price > MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton"; MyGUI::Button* button = mTrainingOptions->createWidget(skin, MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default); @@ -102,12 +102,12 @@ namespace MWGui void TrainingWindow::onReferenceUnavailable () { - mWindowManager.removeGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Training); } void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender) { - mWindowManager.removeGuiMode (GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); } void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender) @@ -123,13 +123,13 @@ namespace MWGui int price = pcStats.getSkill (skillId).getBase() * store.get().find("iTrainingMod")->getInt (); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - if (mWindowManager.getInventoryWindow()->getPlayerGold()getInventoryWindow()->getPlayerGold()messageBox ("#{sServiceTrainingWords}"); return; } @@ -141,11 +141,11 @@ namespace MWGui pcStats.increaseSkill (skillId, *class_, true); // remove gold - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); // go back to game mode - mWindowManager.removeGuiMode (GM_Training); - mWindowManager.removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); // advance time MWBase::Environment::get().getWorld ()->advanceTime (2); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index f2ef1714e..d6be60ae6 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_TRAININGWINDOW_H #define MWGUI_TRAININGWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 465f588b8..b71017166 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -71,7 +71,7 @@ namespace MWGui price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - MyGUI::Button* toAdd = mDestinationsView->createWidget((price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); + MyGUI::Button* toAdd = mDestinationsView->createWidget((price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); mCurrentY += sLineHeight; if(interior) toAdd->setUserString("interior","y"); @@ -129,10 +129,10 @@ namespace MWGui int price; iss >> price; - if (mWindowManager.getInventoryWindow()->getPlayerGold()getInventoryWindow()->getPlayerGold()addOrRemoveGold (-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow ()->addOrRemoveGold (-price); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -156,20 +156,20 @@ namespace MWGui MWBase::Environment::get().getWorld()->advanceTime(time); } MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); - mWindowManager.removeGuiMode(GM_Travel); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0); MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(1); } void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); } void TravelWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, @@ -178,8 +178,8 @@ namespace MWGui void TravelWindow::onReferenceUnavailable() { - mWindowManager.removeGuiMode(GM_Travel); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index cc3d6a31f..61b724910 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -2,7 +2,7 @@ #define MWGUI_TravelWINDOW_H #include "container.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 09eb5c914..69dfa10b4 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -75,7 +75,7 @@ namespace MWGui { if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } int canRest = MWBase::Environment::get().getWorld ()->canRest (); @@ -83,8 +83,8 @@ namespace MWGui if (canRest == 2) { // resting underwater or mid-air not allowed - mWindowManager.messageBox ("#{sNotifyMessage1}"); - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage1}"); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } setCanRest(canRest == 0); @@ -212,7 +212,7 @@ namespace MWGui void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) @@ -263,8 +263,8 @@ namespace MWGui { MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.2); mProgressBar.setVisible (false); - mWindowManager.removeGuiMode (GM_Rest); - mWindowManager.removeGuiMode (GM_RestBed); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); mWaiting = false; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -273,7 +273,7 @@ namespace MWGui // trigger levelup if possible if (mSleeping && pcstats.getLevelProgress () >= 10) { - mWindowManager.pushGuiMode (GM_Levelup); + MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); } } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index c102d0fc6..4510e665b 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_WAIT_DIALOG_H #define MWGUI_WAIT_DIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index e822e047e..3801ae6f7 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -218,8 +218,7 @@ void MWAttribute::initialiseOverride() /* MWSpell */ MWSpell::MWSpell() - : mWindowManager(NULL) - , mSpellNameWidget(NULL) + : mSpellNameWidget(NULL) { } @@ -242,7 +241,6 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::W for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - effect->setWindowManager(mWindowManager); SpellEffectParams params; params.mEffectID = it->mEffectID; params.mSkill = it->mSkill; @@ -262,7 +260,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::W void MWSpell::updateWidgets() { - if (mSpellNameWidget && mWindowManager) + if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -289,8 +287,7 @@ MWSpell::~MWSpell() /* MWEffectList */ MWEffectList::MWEffectList() - : mWindowManager(NULL) - , mEffectList(0) + : mEffectList(0) { } @@ -311,7 +308,6 @@ void MWEffectList::createEffectWidgets(std::vector &effects, MyG it != mEffectList.end(); ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - effect->setWindowManager(mWindowManager); it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; effect->setSpellEffect(*it); @@ -378,8 +374,7 @@ SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() - : mWindowManager(NULL) - , mImageWidget(NULL) + : mImageWidget(NULL) , mTextWidget(NULL) , mRequestedWidth(0) { @@ -409,22 +404,22 @@ void MWSpellEffect::updateWidgets() assert(magicEffect); - std::string pt = mWindowManager->getGameSettingString("spoint", ""); - std::string pts = mWindowManager->getGameSettingString("spoints", ""); - std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " "; - std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); - std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); + std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); + std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; + std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); + std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); - std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); + std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) { - spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); } if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) { - spellLine += " " + mWindowManager->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); } if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) @@ -442,7 +437,7 @@ void MWSpellEffect::updateWidgets() { if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) { - spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); } if (mEffectParams.mArea > 0) @@ -453,13 +448,13 @@ void MWSpellEffect::updateWidgets() // potions have no target if (!mEffectParams.mNoTarget) { - std::string on = mWindowManager->getGameSettingString("sonword", ""); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); if (mEffectParams.mRange == ESM::RT_Self) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); else if (mEffectParams.mRange == ESM::RT_Touch) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); else if (mEffectParams.mRange == ESM::RT_Target) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); } } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 784537c42..26ca75066 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -94,7 +94,6 @@ namespace MWGui typedef MWMechanics::Stat SkillValue; - void setWindowManager(MWBase::WindowManager *m) { mManager = m; } /// \todo remove void setSkillId(ESM::Skill::SkillEnum skillId); void setSkillNumber(int skillId); void setSkillValue(const SkillValue& value); @@ -138,7 +137,6 @@ namespace MWGui typedef MWMechanics::Stat AttributeValue; - void setWindowManager(MWBase::WindowManager *m) { mManager = m; } void setAttributeId(int attributeId); void setAttributeValue(const AttributeValue& value); @@ -185,7 +183,6 @@ namespace MWGui typedef MWMechanics::Stat SpellValue; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellId(const std::string &id); /** @@ -207,7 +204,6 @@ namespace MWGui private: void updateWidgets(); - MWBase::WindowManager* mWindowManager; std::string mId; MyGUI::TextBox* mSpellNameWidget; }; @@ -227,7 +223,6 @@ namespace MWGui EF_Constant = 0x02 // constant effect means that duration will not be displayed }; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setEffectList(const SpellEffectList& list); static SpellEffectList effectListFromESM(const ESM::EffectList* effects); @@ -249,7 +244,6 @@ namespace MWGui private: void updateWidgets(); - MWBase::WindowManager* mWindowManager; SpellEffectList mEffectList; }; typedef MWEffectList* MWEffectListPtr; @@ -262,7 +256,6 @@ namespace MWGui typedef ESM::ENAMstruct SpellEffectValue; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellEffect(const SpellEffectParams& params); int getRequestedWidth() const { return mRequestedWidth; } @@ -276,7 +269,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager* mWindowManager; SpellEffectParams mEffectParams; MyGUI::ImageBox* mImageWidget; MyGUI::TextBox* mTextWidget; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp new file mode 100644 index 000000000..cb3d4ea8c --- /dev/null +++ b/apps/openmw/mwgui/windowbase.cpp @@ -0,0 +1,54 @@ +#include "windowbase.hpp" + +#include + +#include "../mwbase/windowmanager.hpp" + +using namespace MWGui; + +WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : Layout(parLayout) +{ +} + +void WindowBase::setVisible(bool visible) +{ + bool wasVisible = mMainWidget->getVisible(); + mMainWidget->setVisible(visible); + + if (visible) + open(); + else if (wasVisible && !visible) + close(); +} + +void WindowBase::center() +{ + // Centre dialog + + // MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + // Note by scrawl: The following works more reliably in the case when the window was _just_ + // resized and MyGUI RenderManager doesn't know about the new size yet + MyGUI::IntSize gameWindowSize = MyGUI::IntSize(Settings::Manager::getInt("resolution x", "Video"), + Settings::Manager::getInt("resolution y", "Video")); + + MyGUI::IntCoord coord = mMainWidget->getCoord(); + coord.left = (gameWindowSize.width - coord.width)/2; + coord.top = (gameWindowSize.height - coord.height)/2; + mMainWidget->setCoord(coord); +} + +WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : WindowBase(parLayout, parWindowManager) +{ +} + +void WindowModal::open() +{ + MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); +} + +void WindowModal::close() +{ + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); +} diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp new file mode 100644 index 000000000..a2cb731fe --- /dev/null +++ b/apps/openmw/mwgui/windowbase.hpp @@ -0,0 +1,47 @@ +#ifndef MWGUI_WINDOW_BASE_H +#define MWGUI_WINDOW_BASE_H + +#include + +namespace MWBase +{ + class WindowManager; +} + +namespace MWGui +{ + class WindowManager; + + class WindowBase: public OEngine::GUI::Layout + { + public: + WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + + // Events + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; + + virtual void open() {} + virtual void close () {} + virtual void setVisible(bool visible); + void center(); + + /** Event : Dialog finished, OK button clicked.\n + signature : void method()\n + */ + EventHandle_WindowBase eventDone; + }; + + + /* + * "Modal" windows cause the rest of the interface to be unaccessible while they are visible + */ + class WindowModal : public WindowBase + { + public: + WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + virtual void open(); + virtual void close(); + }; +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f994683a6..bcde82e96 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -21,12 +21,12 @@ #include "console.hpp" #include "journalwindow.hpp" #include "charactercreation.hpp" -#include "text_input.hpp" +#include "textinput.hpp" #include "review.hpp" #include "dialogue.hpp" -#include "dialogue_history.hpp" -#include "map_window.hpp" -#include "stats_window.hpp" +#include "dialoguehistory.hpp" +#include "mapwindow.hpp" +#include "statswindow.hpp" #include "messagebox.hpp" #include "container.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp new file mode 100644 index 000000000..54ed082cf --- /dev/null +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -0,0 +1,28 @@ +#include "windowpinnablebase.hpp" + +#include "../mwbase/windowmanager.hpp" + +#include "exposedwindow.hpp" + +using namespace MWGui; + +WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) +{ + ExposedWindow* window = static_cast(mMainWidget); + mPinButton = window->getSkinWidget ("Button"); + + mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); +} + +void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) +{ + mPinned = !mPinned; + + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); + + onPinToggled(); +} diff --git a/apps/openmw/mwgui/windowpinnablebase.hpp b/apps/openmw/mwgui/windowpinnablebase.hpp new file mode 100644 index 000000000..657e8142f --- /dev/null +++ b/apps/openmw/mwgui/windowpinnablebase.hpp @@ -0,0 +1,28 @@ +#ifndef MWGUI_WINDOW_PINNABLE_BASE_H +#define MWGUI_WINDOW_PINNABLE_BASE_H + +#include "windowbase.hpp" + +namespace MWGui +{ + class WindowManager; + + class WindowPinnableBase: public WindowBase + { + public: + WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + bool pinned() { return mPinned; } + + private: + void onPinButtonClicked(MyGUI::Widget* _sender); + + protected: + virtual void onPinToggled() = 0; + + MyGUI::Widget* mPinButton; + bool mPinned; + bool mVisible; + }; +} + +#endif From ad49d1ecab8be0fdd863a5f747f5a680bf1fdc5a Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 10 Apr 2013 15:24:20 +0200 Subject: [PATCH 241/817] Sixth minor fix --- apps/openmw/mwclass/armor.cpp | 6 +++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 6 +++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 18 +++++++++--------- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/actionequip.cpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a14b2667e..d257c8761 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,12 +292,12 @@ namespace MWClass ref->mBase = record; } - int Armor::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); // slots that this item can be equipped in - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::string npcRace = npc.get()->mBase->mRace; @@ -309,7 +309,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = item.get()->mBase->mParts.mParts; + std::vector parts = ptr.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 96c72848c..1b99e5133 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 58c4a2c5c..b4e6e61f6 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,10 +238,10 @@ namespace MWClass ref->mBase = record; } - int Clothing::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { // slots that this item can be equipped in - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::string npcRace = npc.get()->mBase->mRace; @@ -253,7 +253,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = item.get()->mBase->mParts.mParts; + std::vector parts = ptr.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index eb8d80199..71e01e818 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a0cacaf6b..e534a65c2 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,9 +384,9 @@ namespace MWClass ref->mBase = record; } - int Weapon::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); @@ -394,13 +394,13 @@ namespace MWClass { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if(item.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - item.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - item.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - item.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + if(ptr.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + ptr.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + ptr.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { return 2; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 01686b09c..6c3f32abe 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index fd35d0dd3..84d1a3d15 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -21,7 +21,7 @@ namespace MWWorld MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + switch(MWWorld::Class::get (object).canBeEquipped (object, actor)) { case 0: return; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a0067f5d2..d7ff35014 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,7 +259,7 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - int Class::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { return 1; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 362a8bc9c..484004aca 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,7 +242,7 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual Ptr diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 782e3f920..5495d6a02 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -186,7 +186,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - switch(MWWorld::Class::get (test).canBeEquipped (npc, test)) + switch(MWWorld::Class::get (test).canBeEquipped (test, npc)) { case 0: continue; From d768f6b57e2e4b992861a18dedf9e39c6e79b702 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 13:05:15 -0400 Subject: [PATCH 242/817] Deleted *_* files in MwGui, builds. --- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/mwgui/dialogue_history.cpp | 76 --- apps/openmw/mwgui/dialogue_history.hpp | 19 - apps/openmw/mwgui/map_window.cpp | 446 ---------------- apps/openmw/mwgui/map_window.hpp | 107 ---- apps/openmw/mwgui/stats_window.cpp | 580 --------------------- apps/openmw/mwgui/stats_window.hpp | 83 --- apps/openmw/mwgui/text_input.cpp | 69 --- apps/openmw/mwgui/text_input.hpp | 36 -- apps/openmw/mwgui/window_base.cpp | 55 -- apps/openmw/mwgui/window_base.hpp | 51 -- apps/openmw/mwgui/window_pinnable_base.cpp | 28 - apps/openmw/mwgui/window_pinnable_base.hpp | 28 - 13 files changed, 3 insertions(+), 1581 deletions(-) delete mode 100644 apps/openmw/mwgui/dialogue_history.cpp delete mode 100644 apps/openmw/mwgui/dialogue_history.hpp delete mode 100644 apps/openmw/mwgui/map_window.cpp delete mode 100644 apps/openmw/mwgui/map_window.hpp delete mode 100644 apps/openmw/mwgui/stats_window.cpp delete mode 100644 apps/openmw/mwgui/stats_window.hpp delete mode 100644 apps/openmw/mwgui/text_input.cpp delete mode 100644 apps/openmw/mwgui/text_input.hpp delete mode 100644 apps/openmw/mwgui/window_base.cpp delete mode 100644 apps/openmw/mwgui/window_base.hpp delete mode 100644 apps/openmw/mwgui/window_pinnable_base.cpp delete mode 100644 apps/openmw/mwgui/window_pinnable_base.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8a0030be4..b3c3f4134 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -24,9 +24,9 @@ add_openmw_dir (mwinput ) add_openmw_dir (mwgui - text_input widgets race class birth review windowmanagerimp console dialogue - dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base tooltips scrollwindow bookwindow list + textinput widgets race class birth review windowmanagerimp console dialogue + dialoguehistory windowbase statswindow messagebox journalwindow charactercreation + mapwindow windowpinnablebase tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog diff --git a/apps/openmw/mwgui/dialogue_history.cpp b/apps/openmw/mwgui/dialogue_history.cpp deleted file mode 100644 index 13f72545e..000000000 --- a/apps/openmw/mwgui/dialogue_history.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "dialogue_history.hpp" - -#include "../mwbase/windowmanager.hpp" - -#include "widgets.hpp" - -#include "../mwworld/esmstore.hpp" - -#include -#include - -#include -#include - -using namespace MWGui; -using namespace Widgets; - -MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) -{ - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::TextIterator iterator(getCaption()); - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if (pos < _pos) - continue; - else if (pos == _pos) - break; - } - return colour; -} - -MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) -{ - bool breakOnNext = false; - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::UString colour2 = colour; - MyGUI::TextIterator iterator(getCaption()); - MyGUI::TextIterator col_start = iterator; - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if(colour != colour2) - { - if(breakOnNext) - { - return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); - } - col_start = iterator; - colour2 = colour; - } - if (pos < _pos) - continue; - else if (pos == _pos) - { - breakOnNext = true; - } - } - return ""; -} - -void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) -{ - MyGUI::UString head("\n#D8C09A"); - head.append(parText); - head.append("#B29154\n"); - addText(head); -} - -void DialogueHistory::addDialogText(const MyGUI::UString& parText) -{ - addText(parText); - addText("\n"); -} diff --git a/apps/openmw/mwgui/dialogue_history.hpp b/apps/openmw/mwgui/dialogue_history.hpp deleted file mode 100644 index c37504af7..000000000 --- a/apps/openmw/mwgui/dialogue_history.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MWGUI_DIALOGE_HISTORY_H -#define MWGUI_DIALOGE_HISTORY_H -#include - -namespace MWGui -{ - class DialogueHistory : public MyGUI::EditBox - { - MYGUI_RTTI_DERIVED( DialogueHistory ) - public: - Widget* getClient() { return mClient; } - MyGUI::UString getColorAtPos(size_t _pos); - MyGUI::UString getColorTextAt(size_t _pos); - void addDialogHeading(const MyGUI::UString& parText); - void addDialogText(const MyGUI::UString& parText); - }; -} -#endif - diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp deleted file mode 100644 index d0f3f921e..000000000 --- a/apps/openmw/mwgui/map_window.cpp +++ /dev/null @@ -1,446 +0,0 @@ -#include "map_window.hpp" - -#include - -#include -#include -#include - -#include - -#include "../mwbase/windowmanager.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" -#include "../mwworld/player.hpp" - -#include "../mwrender/globalmap.hpp" - -#include "widgets.hpp" - -using namespace MWGui; - -LocalMapBase::LocalMapBase() - : mCurX(0) - , mCurY(0) - , mInterior(false) - , mFogOfWar(true) - , mLocalMap(NULL) - , mMapDragAndDrop(false) - , mPrefix() - , mChanged(true) - , mLayout(NULL) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) - , mLastDirectionX(0.0f) - , mLastDirectionY(0.0f) - , mCompass(NULL) -{ -} - -void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) -{ - mLocalMap = widget; - mLayout = layout; - mMapDragAndDrop = mapDragAndDrop; - mCompass = compass; - - // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each - const int widgetSize = 512; - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", - MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); - - MyGUI::ImageBox* fog = map->createWidget("ImageBox", - MyGUI::IntCoord(0, 0, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); - - if (!mMapDragAndDrop) - { - map->setNeedMouseFocus(false); - fog->setNeedMouseFocus(false); - } - - mMapWidgets.push_back(map); - mFogWidgets.push_back(fog); - } - } -} - -void LocalMapBase::setCellPrefix(const std::string& prefix) -{ - mPrefix = prefix; - mChanged = true; -} - -void LocalMapBase::toggleFogOfWar() -{ - mFogOfWar = !mFogOfWar; - applyFogOfWar(); -} - -void LocalMapBase::applyFogOfWar() -{ - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (-1*(my-1))); - MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) - : ""); - } - } - notifyMapChanged (); -} - -void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::setActiveCell(const int x, const int y, bool interior) -{ - if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell - - // clear all previous markers - for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) - { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") - { - MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); - } - } - - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - // map - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (-1*(my-1))); - - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); - else - box->setImageTexture("black.png"); - - - // door markers - - // interior map only consists of one cell, so handle the markers only once - if (interior && (mx != 2 || my != 2)) - continue; - - MWWorld::CellStore* cell; - if (interior) - cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); - else - cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); - - std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); - - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) - { - MWBase::World::DoorMarker marker = *it; - - // convert world coordinates to normalized cell coordinates - MyGUI::IntCoord widgetCoord; - float nX,nY; - int cellDx, cellDy; - if (!interior) - { - const int cellSize = 8192; - - nX = (marker.x - cellSize * (x+mx-1)) / cellSize; - nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); - } - else - { - Ogre::Vector2 position (marker.x, marker.y); - MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); - } - - static int counter = 0; - ++counter; - MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", marker.name); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); - markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); - - MarkerPosition markerPos; - markerPos.interior = interior; - markerPos.cellX = interior ? cellDx : x + mx - 1; - markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); - markerPos.nX = nX; - markerPos.nY = nY; - - markerWidget->setUserData(markerPos); - } - - - } - } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; - - // fog of war - applyFogOfWar(); - - // set the compass texture again, because MyGUI determines sorting of ImageBox widgets - // based on the last setImageTexture call - std::string tex = "textures\\compass.dds"; - mCompass->setImageTexture(""); - mCompass->setImageTexture(tex); -} - - -void LocalMapBase::setPlayerPos(const float x, const float y) -{ - if (x == mLastPositionX && y == mLastPositionY) - return; - - notifyPlayerUpdate (); - - MyGUI::IntSize size = mLocalMap->getCanvasSize(); - MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); - MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); - mLocalMap->setViewOffset(pos); - - mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); - mLastPositionX = x; - mLastPositionY = y; -} - -void LocalMapBase::setPlayerDir(const float x, const float y) -{ - if (x == mLastDirectionX && y == mLastDirectionY) - return; - - notifyPlayerUpdate (); - - MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(x,y); - rotatingSubskin->setAngle(angle); - - mLastDirectionX = x; - mLastDirectionY = y; -} - -// ------------------------------------------------------------------------------------------ - -MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) - , mGlobal(false) -{ - setCoord(500,0,320,300); - - mGlobalMapRender = new MWRender::GlobalMap(cacheDir); - mGlobalMapRender->render(); - - getWidget(mLocalMap, "LocalMap"); - getWidget(mGlobalMap, "GlobalMap"); - getWidget(mGlobalMapImage, "GlobalMapImage"); - getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); - getWidget(mPlayerArrowLocal, "CompassLocal"); - getWidget(mPlayerArrowGlobal, "CompassGlobal"); - - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); - - mGlobalMap->setVisible (false); - - getWidget(mButton, "WorldButton"); - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing("#{sWorld}"); - - getWidget(mEventBoxGlobal, "EventBoxGlobal"); - mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - getWidget(mEventBoxLocal, "EventBoxLocal"); - mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - - LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); -} - -MapWindow::~MapWindow() -{ - delete mGlobalMapRender; -} - -void MapWindow::setCellName(const std::string& cellName) -{ - setTitle("#{sCell=" + cellName + "}"); -} - -void MapWindow::addVisitedLocation(const std::string& name, int x, int y) -{ - float worldX, worldY; - mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); - - MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+6, - worldY * mGlobalMapRender->getHeight()+6, - 12, 12); - - - static int _counter=0; - MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); - ++_counter; - - markerWidget = mEventBoxGlobal->createWidget("", - widgetCoord, MyGUI::Align::Default); - markerWidget->setNeedMouseFocus (true); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); -} - -void MapWindow::cellExplored(int x, int y) -{ - mGlobalMapRender->exploreCell(x,y); -} - -void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - - MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - - if (!mGlobal) - mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); - else - mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); - - - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) -{ - mGlobal = !mGlobal; - mGlobalMap->setVisible(mGlobal); - mLocalMap->setVisible(!mGlobal); - - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); - - if (mGlobal) - globalMapUpdatePlayer (); -} - -void MapWindow::onPinToggled() -{ - mWindowManager.setMinimapVisibility(!mPinned); -} - -void MapWindow::open() -{ - mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - - for (unsigned int i=0; igetChildCount (); ++i) - { - if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") - mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); - } - - globalMapUpdatePlayer(); - - mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); -} - -void MapWindow::globalMapUpdatePlayer () -{ - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); - Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - - // for interiors, we have no choice other than using the last position & direction. - /// \todo save this last position in the savegame? - if (MWBase::Environment::get().getWorld ()->isCellExterior ()) - { - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); - - MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(dir.x, dir.y); - rotatingSubskin->setAngle(angle); - - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); - mGlobalMap->setViewOffset(viewoffs); - } -} - -void MapWindow::notifyPlayerUpdate () -{ - globalMapUpdatePlayer (); -} - -void MapWindow::notifyMapChanged () -{ - // workaround to prevent the map from drawing on top of the button - MyGUI::IntCoord oldCoord = mButton->getCoord (); - MyGUI::Gui::getInstance().destroyWidget (mButton); - mButton = mMainWidget->createWidget("MW_Button", - oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); - mButton->setProperty ("ExpandDirection", "Left"); - - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); -} diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp deleted file mode 100644 index 39770a7a2..000000000 --- a/apps/openmw/mwgui/map_window.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef MWGUI_MAPWINDOW_H -#define MWGUI_MAPWINDOW_H - -#include "window_pinnable_base.hpp" - -namespace MWRender -{ - class GlobalMap; -} - -namespace MWGui -{ - class LocalMapBase - { - public: - LocalMapBase(); - void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false); - - void setCellPrefix(const std::string& prefix); - void setActiveCell(const int x, const int y, bool interior=false); - void setPlayerDir(const float x, const float y); - void setPlayerPos(const float x, const float y); - - void toggleFogOfWar(); - - struct MarkerPosition - { - bool interior; - int cellX; - int cellY; - float nX; - float nY; - }; - - protected: - int mCurX, mCurY; - bool mInterior; - MyGUI::ScrollView* mLocalMap; - MyGUI::ImageBox* mCompass; - std::string mPrefix; - bool mChanged; - bool mFogOfWar; - - std::vector mMapWidgets; - std::vector mFogWidgets; - - void applyFogOfWar(); - - void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); - void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); - - virtual void notifyPlayerUpdate() {} - virtual void notifyMapChanged() {} - - OEngine::GUI::Layout* mLayout; - - bool mMapDragAndDrop; - - float mLastPositionX; - float mLastPositionY; - float mLastDirectionX; - float mLastDirectionY; - }; - - class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase - { - public: - MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); - virtual ~MapWindow(); - - void setCellName(const std::string& cellName); - - void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map - void cellExplored(int x, int y); - - virtual void open(); - - private: - void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); - void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); - void onWorldButtonClicked(MyGUI::Widget* _sender); - - void globalMapUpdatePlayer(); - - MyGUI::ScrollView* mGlobalMap; - MyGUI::ImageBox* mGlobalMapImage; - MyGUI::ImageBox* mGlobalMapOverlay; - MyGUI::ImageBox* mPlayerArrowLocal; - MyGUI::ImageBox* mPlayerArrowGlobal; - MyGUI::Button* mButton; - MyGUI::IntPoint mLastDragPos; - bool mGlobal; - - MyGUI::Button* mEventBoxGlobal; - MyGUI::Button* mEventBoxLocal; - - MWRender::GlobalMap* mGlobalMapRender; - - protected: - virtual void onPinToggled(); - - virtual void notifyPlayerUpdate(); - virtual void notifyMapChanged(); - - }; -} -#endif diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp deleted file mode 100644 index 0678e9891..000000000 --- a/apps/openmw/mwgui/stats_window.cpp +++ /dev/null @@ -1,580 +0,0 @@ -#include "stats_window.hpp" - -#include -#include -#include - -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwworld/player.hpp" -#include "../mwworld/class.hpp" - -#include "../mwmechanics/npcstats.hpp" - -#include "tooltips.hpp" - - -using namespace MWGui; -const int StatsWindow::sLineHeight = 18; - -StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) - , mSkillView(NULL) - , mClientHeight(0) - , mMajorSkills() - , mMinorSkills() - , mMiscSkills() - , mSkillValues() - , mSkillWidgetMap() - , mFactionWidgetMap() - , mFactions() - , mBirthSignId() - , mReputation(0) - , mBounty(0) - , mSkillWidgets() - , mChanged(true) -{ - setCoord(0,0,498, 342); - - const char *names[][2] = - { - { "Attrib1", "sAttributeStrength" }, - { "Attrib2", "sAttributeIntelligence" }, - { "Attrib3", "sAttributeWillpower" }, - { "Attrib4", "sAttributeAgility" }, - { "Attrib5", "sAttributeSpeed" }, - { "Attrib6", "sAttributeEndurance" }, - { "Attrib7", "sAttributePersonality" }, - { "Attrib8", "sAttributeLuck" }, - { 0, 0 } - }; - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for (int i=0; names[i][0]; ++i) - { - setText (names[i][0], store.get().find (names[i][1])->getString()); - } - - getWidget(mSkillView, "SkillView"); - getWidget(mLeftPane, "LeftPane"); - getWidget(mRightPane, "RightPane"); - - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); - } - - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); -} - -void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); -} - -void StatsWindow::onWindowResize(MyGUI::Window* window) -{ - mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); - mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) -{ - MyGUI::ProgressPtr pt; - getWidget(pt, name); - pt->setProgressRange(max); - pt->setProgressPosition(val); - - std::stringstream out; - out << val << "/" << max; - setText(tname, out.str().c_str()); -} - -void StatsWindow::setPlayerName(const std::string& playerName) -{ - static_cast(mMainWidget)->setCaption(playerName); - adjustWindowCaption(); -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 - }; - - for (int i=0; ids[i]; ++i) - if (ids[i]==id) - { - std::ostringstream valueString; - valueString << value.getModified(); - setText (id, valueString.str()); - - MyGUI::TextBox* box; - getWidget(box, id); - - if (value.getModified()>value.getBase()) - box->_setWidgetState("increased"); - else if (value.getModified()_setWidgetState("decreased"); - else - box->_setWidgetState("normal"); - - break; - } -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = - { - "HBar", "MBar", "FBar", - 0 - }; - - for (int i=0; ids[i]; ++i) - { - if (ids[i]==id) - { - std::string id (ids[i]); - setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); - - // health, magicka, fatigue tooltip - MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - if (i==0) - { - getWidget(w, "Health"); - w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); - } - else if (i==1) - { - getWidget(w, "Magicka"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); - } - else if (i==2) - { - getWidget(w, "Fatigue"); - w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); - } - } - } -} - -void StatsWindow::setValue (const std::string& id, const std::string& value) -{ - if (id=="name") - setPlayerName (value); - else if (id=="race") - setText ("RaceText", value); - else if (id=="class") - setText ("ClassText", value); -} - -void StatsWindow::setValue (const std::string& id, int value) -{ - if (id=="level") - { - std::ostringstream text; - text << value; - setText("LevelText", text.str()); - } -} - -void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) -{ - mSkillValues[parSkill] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } -} - -void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); - } - - updateSkillArea(); -} - -void StatsWindow::onFrame () -{ - if (!mMainWidget->getVisible()) - return; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - - // level progress - MyGUI::Widget* levelWidget; - for (int i=0; i<2; ++i) - { - getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); - levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); - levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); - } - - setFactions(PCstats.getFactionRanks()); - setExpelled(PCstats.getExpelled ()); - - const std::string &signId = - MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); - - setBirthSign(signId); - setReputation (PCstats.getReputation ()); - setBounty (PCstats.getBounty ()); - - if (mChanged) - updateSkillArea(); -} - -void StatsWindow::setFactions (const FactionList& factions) -{ - if (mFactions != factions) - { - mFactions = factions; - mChanged = true; - } -} - -void StatsWindow::setExpelled (const std::set& expelled) -{ - if (mExpelled != expelled) - { - mExpelled = expelled; - mChanged = true; - } -} - -void StatsWindow::setBirthSign (const std::string& signId) -{ - if (signId != mBirthSignId) - { - mBirthSignId = signId; - mChanged = true; - } -} - -void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", - MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", - MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - groupWidget->setCaption(label); - groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox *skillNameWidget, *skillValueWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillNameWidget; -} - -void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); - } - - addGroup(mWindowManager.getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) - { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - int progressPercent = (modified - float(static_cast(modified))) * 100; - - const MWWorld::ESMStore &esmStore = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Skill* skill = esmStore.get().find(skillId); - assert(skill); - - std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; - - const ESM::Attribute* attr = - esmStore.get().find(skill->mData.mAttribute); - assert(attr); - - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), - boost::lexical_cast(static_cast(modified)), state, coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); - } - - mSkillWidgetMap[skillId] = widget; - } -} - -void StatsWindow::updateSkillArea() -{ - mChanged = false; - - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillWidgets.clear(); - - mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); - mClientHeight = 0; - - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); - - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); - - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); - - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - - MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::ESMStore &store = world->getStore(); - const ESM::NPC *player = - world->getPlayer().getPlayer().get()->mBase; - - // race tooltip - const ESM::Race* playerRace = store.get().find(player->mRace); - - MyGUI::Widget* raceWidget; - getWidget(raceWidget, "RaceText"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - getWidget(raceWidget, "Race_str"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - - // class tooltip - MyGUI::Widget* classWidget; - - const ESM::Class *playerClass = - store.get().find(player->mClass); - - getWidget(classWidget, "ClassText"); - ToolTips::createClassToolTip(classWidget, *playerClass); - getWidget(classWidget, "Class_str"); - ToolTips::createClassToolTip(classWidget, *playerClass); - - if (!mFactions.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - std::set& expelled = PCstats.getExpelled (); - - addGroup(mWindowManager.getGameSettingString("sFaction", "Faction"), coord1, coord2); - FactionList::const_iterator end = mFactions.end(); - for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) - { - const ESM::Faction *faction = - store.get().find(it->first); - MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); - - std::string text; - - text += std::string("#DDC79E") + faction->mName; - - if (expelled.find(it->first) != expelled.end()) - text += "\n#{sExpelled}"; - else - { - text += std::string("\n#BF9959") + faction->mRanks[it->second]; - - if (it->second < 9) - { - // player doesn't have max rank yet - text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; - - ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - assert(attr1 && attr2); - - text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); - - text += "\n\n#DDC79E#{sFavoriteSkills}"; - text += "\n#BF9959"; - for (int i=0; i<6; ++i) - { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; - if (i<5) - text += ", "; - } - - text += "\n"; - - if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); - if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); - } - } - - w->setUserString("ToolTipType", "Layout"); - w->setUserString("ToolTipLayout", "TextToolTip"); - w->setUserString("Caption_Text", text); - } - } - - if (!mBirthSignId.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); - const ESM::BirthSign *sign = - store.get().find(mBirthSignId); - MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); - - ToolTips::createBirthsignToolTip(w, mBirthSignId); - } - - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); - } - - addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); - } - - mClientHeight = coord1.top; - - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::onPinToggled() -{ - mWindowManager.setHMSVisibility(!mPinned); -} diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp deleted file mode 100644 index 3befc1f00..000000000 --- a/apps/openmw/mwgui/stats_window.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef MWGUI_STATS_WINDOW_H -#define MWGUI_STATS_WINDOW_H - -#include "../mwworld/esmstore.hpp" - -#include -#include -#include -#include - -#include "../mwmechanics/stat.hpp" -#include "window_pinnable_base.hpp" - -namespace MWGui -{ - class WindowManager; - - class StatsWindow : public WindowPinnableBase - { - public: - typedef std::map FactionList; - - typedef std::vector SkillList; - - StatsWindow(MWBase::WindowManager& parWindowManager); - - /// automatically updates all the data in the stats window, but only if it has changed. - void onFrame(); - - void setBar(const std::string& name, const std::string& tname, int val, int max); - void setPlayerName(const std::string& playerName); - - /// Set value for the given ID. - void setValue (const std::string& id, const MWMechanics::Stat& value); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setValue (const std::string& id, const std::string& value); - void setValue (const std::string& id, int value); - void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); - - void configureSkills (const SkillList& major, const SkillList& minor); - void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } - void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } - void updateSkillArea(); - - private: - void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - - void setFactions (const FactionList& factions); - void setExpelled (const std::set& expelled); - void setBirthSign (const std::string &signId); - - void onWindowResize(MyGUI::Window* window); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); - - static const int sLineHeight; - - MyGUI::Widget* mLeftPane; - MyGUI::Widget* mRightPane; - - MyGUI::ScrollView* mSkillView; - int mLastPos, mClientHeight; - - SkillList mMajorSkills, mMinorSkills, mMiscSkills; - std::map > mSkillValues; - std::map mSkillWidgetMap; - std::map mFactionWidgetMap; - FactionList mFactions; ///< Stores a list of factions and the current rank - std::string mBirthSignId; - int mReputation, mBounty; - std::vector mSkillWidgets; //< Skills and other information - std::set mExpelled; - - bool mChanged; - - protected: - virtual void onPinToggled(); - }; -} -#endif diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp deleted file mode 100644 index ee9144be6..000000000 --- a/apps/openmw/mwgui/text_input.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "text_input.hpp" - -#include "../mwbase/windowmanager.hpp" - -using namespace MWGui; - -TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_text_input.layout", parWindowManager) -{ - // Centre dialog - center(); - - getWidget(mTextEdit, "TextEdit"); - mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -void TextInputDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); - else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); -} - -void TextInputDialog::setTextLabel(const std::string &label) -{ - setText("LabelT", label); -} - -void TextInputDialog::open() -{ - WindowModal::open(); - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -// widget controls - -void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if (mTextEdit->getCaption() == "") - { - mWindowManager.messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} - -void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) -{ - if (mTextEdit->getCaption() == "") - { - mWindowManager.messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp deleted file mode 100644 index 29de7388b..000000000 --- a/apps/openmw/mwgui/text_input.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MWGUI_TEXT_INPUT_H -#define MWGUI_TEXT_INPUT_H - -#include "window_base.hpp" - -namespace MWGui -{ - class WindowManager; -} - -/* - */ - -namespace MWGui -{ - class TextInputDialog : public WindowModal - { - public: - TextInputDialog(MWBase::WindowManager& parWindowManager); - - std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } - void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } - - void setNextButtonShow(bool shown); - void setTextLabel(const std::string &label); - virtual void open(); - - protected: - void onOkClicked(MyGUI::Widget* _sender); - void onTextAccepted(MyGUI::Edit* _sender); - - private: - MyGUI::EditBox* mTextEdit; - }; -} -#endif diff --git a/apps/openmw/mwgui/window_base.cpp b/apps/openmw/mwgui/window_base.cpp deleted file mode 100644 index 38bee9ea3..000000000 --- a/apps/openmw/mwgui/window_base.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "window_base.hpp" - -#include - -#include "../mwbase/windowmanager.hpp" - -using namespace MWGui; - -WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : Layout(parLayout) - , mWindowManager(parWindowManager) -{ -} - -void WindowBase::setVisible(bool visible) -{ - bool wasVisible = mMainWidget->getVisible(); - mMainWidget->setVisible(visible); - - if (visible) - open(); - else if (wasVisible && !visible) - close(); -} - -void WindowBase::center() -{ - // Centre dialog - - // MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - // Note by scrawl: The following works more reliably in the case when the window was _just_ - // resized and MyGUI RenderManager doesn't know about the new size yet - MyGUI::IntSize gameWindowSize = MyGUI::IntSize(Settings::Manager::getInt("resolution x", "Video"), - Settings::Manager::getInt("resolution y", "Video")); - - MyGUI::IntCoord coord = mMainWidget->getCoord(); - coord.left = (gameWindowSize.width - coord.width)/2; - coord.top = (gameWindowSize.height - coord.height)/2; - mMainWidget->setCoord(coord); -} - -WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager) -{ -} - -void WindowModal::open() -{ - MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); -} - -void WindowModal::close() -{ - MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); -} diff --git a/apps/openmw/mwgui/window_base.hpp b/apps/openmw/mwgui/window_base.hpp deleted file mode 100644 index afdf4d065..000000000 --- a/apps/openmw/mwgui/window_base.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef MWGUI_WINDOW_BASE_H -#define MWGUI_WINDOW_BASE_H - -#include - -namespace MWBase -{ - class WindowManager; -} - -namespace MWGui -{ - class WindowManager; - - class WindowBase: public OEngine::GUI::Layout - { - public: - WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - - // Events - typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; - - virtual void open() {} - virtual void close () {} - virtual void setVisible(bool visible); - void center(); - - /** Event : Dialog finished, OK button clicked.\n - signature : void method()\n - */ - EventHandle_WindowBase eventDone; - - protected: - /// \todo remove - MWBase::WindowManager& mWindowManager; - }; - - - /* - * "Modal" windows cause the rest of the interface to be unaccessible while they are visible - */ - class WindowModal : public WindowBase - { - public: - WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - virtual void open(); - virtual void close(); - }; -} - -#endif diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp deleted file mode 100644 index 651b3a1e9..000000000 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "window_pinnable_base.hpp" - -#include "../mwbase/windowmanager.hpp" - -#include "exposedwindow.hpp" - -using namespace MWGui; - -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) -{ - ExposedWindow* window = static_cast(mMainWidget); - mPinButton = window->getSkinWidget ("Button"); - - mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); -} - -void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) -{ - mPinned = !mPinned; - - if (mPinned) - mPinButton->changeWidgetSkin ("PinDown"); - else - mPinButton->changeWidgetSkin ("PinUp"); - - onPinToggled(); -} diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp deleted file mode 100644 index 50259858e..000000000 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MWGUI_WINDOW_PINNABLE_BASE_H -#define MWGUI_WINDOW_PINNABLE_BASE_H - -#include "window_base.hpp" - -namespace MWGui -{ - class WindowManager; - - class WindowPinnableBase: public WindowBase - { - public: - WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - bool pinned() { return mPinned; } - - private: - void onPinButtonClicked(MyGUI::Widget* _sender); - - protected: - virtual void onPinToggled() = 0; - - MyGUI::Widget* mPinButton; - bool mPinned; - bool mVisible; - }; -} - -#endif From d61ec1063e7c008ea2a1b6a1d90b60d94de85624 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 20:14:10 +0200 Subject: [PATCH 243/817] added script editor --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 25 +++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/view/world/scriptsubview.cpp | 92 ++++++++++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 62 ++++++++++++++++ apps/opencs/view/world/subviews.cpp | 2 + 7 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/world/scriptsubview.cpp create mode 100644 apps/opencs/view/world/scriptsubview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 76d4280c8..bd882892f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -55,7 +55,7 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world - table tablesubview + table tablesubview scriptsubview ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 23049164f..fea618037 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -35,7 +35,8 @@ namespace CSMWorld Display_Specialisation, Display_Attribute, Display_Boolean, - Display_SpellType + Display_SpellType, + Display_Script }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6d6d1b1ef..9242e8a23 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -723,6 +723,31 @@ namespace CSMWorld return true; } }; + + template + struct ScriptColumn : public Column + { + ScriptColumn() : Column ("Script", ColumnBase::Display_Script, 0) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mScriptText.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mScriptText = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 14aff47e8..9f6b186c0 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -93,6 +93,7 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); mScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Script)); + mScripts.addColumn (new ScriptColumn); mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp new file mode 100644 index 000000000..2fdb44aec --- /dev/null +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -0,0 +1,92 @@ + +#include "scriptsubview.hpp" + +#include + +#include + +#include "../../model/doc/document.hpp" +#include "../../model/world/universalid.hpp" +#include "../../model/world/data.hpp" +#include "../../model/world/columnbase.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" + +CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) +{ + ++mView.mChangeLocked; +} + +CSVWorld::ScriptSubView::ChangeLock::~ChangeLock() +{ + --mView.mChangeLocked; +} + +CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0) +{ + setWidget (mEditor = new QTextEdit (this)); + + mEditor->setAcceptRichText (false); + mEditor->setLineWrapMode (QTextEdit::NoWrap); + mEditor->setTabStopWidth (4); + mEditor->setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead + + mModel = &dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); + + for (int i=0; icolumnCount(); ++i) + if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== + CSMWorld::ColumnBase::Display_Script) + { + mColumn = i; + break; + } + + if (mColumn==-1) + throw std::logic_error ("Can't find script column"); + + mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + + connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); + + connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); + +// connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int start, int end)), +// this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int start, int end))); +} + +void CSVWorld::ScriptSubView::setEditLock (bool locked) +{ + mEditor->setReadOnly (locked); +} + +void CSVWorld::ScriptSubView::textChanged() +{ + ChangeLock lock (*this); + + mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, + mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText())); +} + +void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + if (mChangeLocked) + return; + + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + + if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && + index.column()>=topLeft.column() && index.column()<=bottomRight.column()) + { + QTextCursor cursor = mEditor->textCursor(); + mEditor->setPlainText (mModel->data (index).toString()); + mEditor->setTextCursor (cursor); + } +} + +void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + +} \ No newline at end of file diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp new file mode 100644 index 000000000..07d87d947 --- /dev/null +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -0,0 +1,62 @@ +#ifndef CSV_WORLD_SCRIPTSUBVIEW_H +#define CSV_WORLD_SCRIPTSUBVIEW_H + +#include "../doc/subview.hpp" + +class QTextEdit; +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class IdTable; +} + +namespace CSVWorld +{ + class ScriptSubView : public CSVDoc::SubView + { + Q_OBJECT + + QTextEdit *mEditor; + CSMDoc::Document& mDocument; + CSMWorld::IdTable *mModel; + int mColumn; + int mChangeLocked; + + class ChangeLock + { + ScriptSubView& mView; + + ChangeLock (const ChangeLock&); + ChangeLock& operator= (const ChangeLock&); + + public: + + ChangeLock (ScriptSubView& view); + ~ChangeLock(); + }; + + friend class ChangeLock; + + public: + + ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + private slots: + + void textChanged(); + + void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index c9ef4df8d..8f7887f3b 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -5,6 +5,7 @@ #include "tablesubview.hpp" #include "dialoguesubview.hpp" +#include "scriptsubview.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -32,6 +33,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) for (int i=0; sTableTypes[i]!=CSMWorld::UniversalId::Type_None; ++i) manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory); // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); From f7383905b7ca21a6aae6dd438ce0cc948eedf2be Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 14:46:21 -0400 Subject: [PATCH 244/817] Finally eliminated calls to MWBase::WindowManager in constructors --- apps/openmw/mwgui/alchemywindow.cpp | 4 +- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/birth.cpp | 4 +- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 4 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.cpp | 197 +++++++++++----------- apps/openmw/mwgui/charactercreation.hpp | 4 +- apps/openmw/mwgui/class.cpp | 44 ++--- apps/openmw/mwgui/class.hpp | 18 +- apps/openmw/mwgui/companionwindow.cpp | 4 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.cpp | 4 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/container.cpp | 4 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.cpp | 4 +- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 10 +- apps/openmw/mwgui/dialogue.hpp | 4 +- apps/openmw/mwgui/enchantingdialog.cpp | 10 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 4 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/itemselection.cpp | 4 +- apps/openmw/mwgui/itemselection.hpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 +- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/levelupdialog.cpp | 4 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 4 +- apps/openmw/mwgui/loadingscreen.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 4 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/merchantrepair.cpp | 4 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 4 +- apps/openmw/mwgui/messagebox.hpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 18 +- apps/openmw/mwgui/quickkeysmenu.hpp | 6 +- apps/openmw/mwgui/race.cpp | 4 +- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 4 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 4 +- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 4 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 4 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 18 +- apps/openmw/mwgui/spellcreationdialog.hpp | 6 +- apps/openmw/mwgui/spellwindow.cpp | 4 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 4 +- apps/openmw/mwgui/statswindow.hpp | 2 +- apps/openmw/mwgui/textinput.cpp | 4 +- apps/openmw/mwgui/textinput.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 4 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 4 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 4 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 10 +- apps/openmw/mwgui/waitdialog.hpp | 4 +- apps/openmw/mwgui/widgets.cpp | 14 +- apps/openmw/mwgui/widgets.hpp | 4 - apps/openmw/mwgui/windowbase.cpp | 6 +- apps/openmw/mwgui/windowbase.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 58 +++---- apps/openmw/mwgui/windowpinnablebase.cpp | 4 +- apps/openmw/mwgui/windowpinnablebase.hpp | 2 +- 77 files changed, 300 insertions(+), 309 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 1ae534797..a6121c234 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -26,8 +26,8 @@ namespace namespace MWGui { - AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_alchemy_window.layout", parWindowManager) + AlchemyWindow::AlchemyWindow() + : WindowBase("openmw_alchemy_window.layout") , ContainerBase(0), mApparatus (4), mIngredients (4) { getWidget(mCreateButton, "CreateButton"); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 933975f0c..c61d2f92b 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -14,7 +14,7 @@ namespace MWGui class AlchemyWindow : public WindowBase, public ContainerBase { public: - AlchemyWindow(MWBase::WindowManager& parWindowManager); + AlchemyWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index d899ab00b..133bbd32f 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -24,8 +24,8 @@ bool sortBirthSigns(const std::pair& left, c } -BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_birth.layout", parWindowManager) +BirthDialog::BirthDialog() + : WindowModal("openmw_chargen_birth.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 033501f22..cc958ddca 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -13,7 +13,7 @@ namespace MWGui class BirthDialog : public WindowModal { public: - BirthDialog(MWBase::WindowManager& parWindowManager); + BirthDialog(); enum Gender { diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index d57953d07..ce74c4859 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -14,8 +14,8 @@ using namespace MWGui; -BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_book.layout", parWindowManager) +BookWindow::BookWindow () + : WindowBase("openmw_book.layout") , mTakeButtonShow(true) , mTakeButtonAllowed(true) { diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index c2a9dca89..9123969e0 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -12,7 +12,7 @@ namespace MWGui class BookWindow : public WindowBase { public: - BookWindow(MWBase::WindowManager& parWindowManager); + BookWindow(); void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 27de7cee9..0dd6502c6 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -47,7 +47,7 @@ namespace using namespace MWGui; -CharacterCreation::CharacterCreation(MWBase::WindowManager* _wm) +CharacterCreation::CharacterCreation() : mNameDialog(0) , mRaceDialog(0) , mClassChoiceDialog(0) @@ -58,7 +58,6 @@ CharacterCreation::CharacterCreation(MWBase::WindowManager* _wm) , mBirthSignDialog(0) , mReviewDialog(0) , mGenerateClassStep(0) - , mWM(_wm) { mCreationStage = CSE_NotStarted; } @@ -118,10 +117,10 @@ void CharacterCreation::spawnDialog(const char id) switch (id) { case GM_Name: - mWM->removeDialog(mNameDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = 0; - mNameDialog = new TextInputDialog(*mWM); - mNameDialog->setTextLabel(mWM->getGameSettingString("sName", "Name")); + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); mNameDialog->setTextInput(mPlayerName); mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); @@ -129,9 +128,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Race: - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; - mRaceDialog = new RaceDialog(*mWM); + mRaceDialog = new RaceDialog(); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); @@ -142,9 +141,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Class: - mWM->removeDialog(mClassChoiceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(*mWM); + mClassChoiceDialog = new ClassChoiceDialog(); mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); mClassChoiceDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) @@ -152,9 +151,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_ClassPick: - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(*mWM); + mPickClassDialog = new PickClassDialog(); mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mPickClassDialog->setClassId(mPlayerClass.mName); mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); @@ -165,9 +164,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Birth: - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(*mWM); + mBirthSignDialog = new BirthDialog(); mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); mBirthSignDialog->setBirthId(mPlayerBirthSignId); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); @@ -178,9 +177,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_ClassCreate: - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mCreateClassDialog = new CreateClassDialog(*mWM); + mCreateClassDialog = new CreateClassDialog(); mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); @@ -199,9 +198,9 @@ void CharacterCreation::spawnDialog(const char id) mCreationStage = CSE_RaceChosen; break; case GM_Review: - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mReviewDialog = new ReviewDialog(*mWM); + mReviewDialog = new ReviewDialog(); mReviewDialog->setPlayerName(mPlayerName); mReviewDialog->setRace(mPlayerRaceId); mReviewDialog->setClass(mPlayerClass); @@ -212,7 +211,7 @@ void CharacterCreation::spawnDialog(const char id) mReviewDialog->setFatigue(mPlayerFatigue); { - std::map > attributes = mWM->getPlayerAttributeValues(); + std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); for (std::map >::iterator it = attributes.begin(); it != attributes.end(); ++it) { @@ -221,13 +220,13 @@ void CharacterCreation::spawnDialog(const char id) } { - std::map > skills = mWM->getPlayerSkillValues(); + std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); for (std::map >::iterator it = skills.begin(); it != skills.end(); ++it) { mReviewDialog->setSkillValue(static_cast (it->first), it->second); } - mReviewDialog->configureSkills(mWM->getPlayerMajorSkills(), mWM->getPlayerMinorSkills()); + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); } mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); @@ -257,41 +256,41 @@ void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } void CharacterCreation::onReviewDialogBack() { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } void CharacterCreation::onReviewActivateDialog(int parDialog) { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; mCreationStage = CSE_ReviewNext; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); switch(parDialog) { case ReviewDialog::NAME_DIALOG: - mWM->pushGuiMode(GM_Name); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); break; case ReviewDialog::RACE_DIALOG: - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); break; case ReviewDialog::CLASS_DIALOG: - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); break; case ReviewDialog::BIRTHSIGN_DIALOG: - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); }; } @@ -308,27 +307,27 @@ void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) if (klass) { mPlayerClass = *klass; - mWM->setPlayerClass(mPlayerClass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); } - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; } //TODO This bit gets repeated a few times; wrap it in a function if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -339,34 +338,34 @@ void CharacterCreation::onPickClassDialogBack() const std::string classId = mPickClassDialog->getClassId(); if (!classId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onClassChoice(int _index) { - mWM->removeDialog(mClassChoiceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = 0; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); switch(_index) { case ClassChoiceDialog::Class_Generate: - mWM->pushGuiMode(GM_ClassGenerate); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); break; case ClassChoiceDialog::Class_Pick: - mWM->pushGuiMode(GM_ClassPick); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); break; case ClassChoiceDialog::Class_Create: - mWM->pushGuiMode(GM_ClassCreate); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); break; case ClassChoiceDialog::Class_Back: - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); break; }; @@ -377,26 +376,26 @@ void CharacterCreation::onNameDialogDone(WindowBase* parWindow) if (mNameDialog) { mPlayerName = mNameDialog->getTextInput(); - mWM->setValue("name", mPlayerName); + MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); - mWM->removeDialog(mNameDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_NameChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); } else { mCreationStage = CSE_NameChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -414,12 +413,12 @@ void CharacterCreation::onRaceDialogBack() data.mHair ); } - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Name); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); } void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) @@ -436,26 +435,26 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) data.mHair ); } - mWM->getInventoryWindow()->rebuildAvatar(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_RaceChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } else { mCreationStage = CSE_RaceChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -466,19 +465,19 @@ void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) mPlayerBirthSignId = mBirthSignDialog->getBirthId(); if (!mPlayerBirthSignId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; } if (mCreationStage >= CSE_BirthSignChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else { mCreationStage = CSE_BirthSignChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -487,12 +486,12 @@ void CharacterCreation::onBirthSignDialogBack() if (mBirthSignDialog) { MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) @@ -522,49 +521,49 @@ void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); mPlayerClass = klass; - mWM->setPlayerClass(klass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } void CharacterCreation::onCreateClassDialogBack() { - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onClassQuestionChosen(int _index) { MWBase::Environment::get().getSoundManager()->stopSay(); - mWM->removeDialog(mGenerateClassQuestionDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); mGenerateClassQuestionDialog = 0; if (_index < 0 || _index >= 3) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); return; } @@ -637,10 +636,10 @@ void CharacterCreation::showClassQuestionDialog() } } - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; - mGenerateClassResultDialog = new GenerateClassResultDialog(*mWM); + mGenerateClassResultDialog = new GenerateClassResultDialog(); mGenerateClassResultDialog->setClassId(mGenerateClass); mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); @@ -650,15 +649,15 @@ void CharacterCreation::showClassQuestionDialog() if (mGenerateClassStep > 10) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); return; } - mWM->removeDialog(mGenerateClassQuestionDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); mGenerateClassQuestionDialog = 0; - mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM); + mGenerateClassQuestionDialog = new InfoBoxDialog(); InfoBoxDialog::ButtonList buttons; mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); @@ -674,18 +673,18 @@ void CharacterCreation::showClassQuestionDialog() void CharacterCreation::onGenerateClassBack() { - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); @@ -694,22 +693,22 @@ void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); mPlayerClass = *klass; - mWM->setPlayerClass(mPlayerClass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 9653aeede..fed77e889 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -29,7 +29,7 @@ namespace MWGui public: typedef std::vector SkillList; - CharacterCreation(MWBase::WindowManager* _wm); + CharacterCreation(); ~CharacterCreation(); //Show a dialog @@ -58,8 +58,6 @@ namespace MWGui BirthDialog* mBirthSignDialog; ReviewDialog* mReviewDialog; - MWBase::WindowManager* mWM; - //Player data std::string mPlayerName; std::string mPlayerRaceId; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 8c352d508..6edad9e83 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -20,8 +20,8 @@ using namespace MWGui; /* GenerateClassResultDialog */ -GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_generate_class_result.layout", parWindowManager) +GenerateClassResultDialog::GenerateClassResultDialog() + : WindowModal("openmw_chargen_generate_class_result.layout") { // Centre dialog center(); @@ -67,8 +67,8 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) /* PickClassDialog */ -PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_class.layout", parWindowManager) +PickClassDialog::PickClassDialog() + : WindowModal("openmw_chargen_class.layout") { // Centre dialog center(); @@ -272,8 +272,8 @@ void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) widget->setSize(width, pos); } -InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_infobox.layout", parWindowManager) +InfoBoxDialog::InfoBoxDialog() + : WindowModal("openmw_infobox.layout") , mCurrentButton(-1) { getWidget(mTextBox, "TextBox"); @@ -356,8 +356,8 @@ void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) /* ClassChoiceDialog */ -ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) - : InfoBoxDialog(parWindowManager) +ClassChoiceDialog::ClassChoiceDialog() + : InfoBoxDialog() { setText(""); ButtonList buttons; @@ -370,8 +370,8 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) /* CreateClassDialog */ -CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_create_class.layout", parWindowManager) +CreateClassDialog::CreateClassDialog() + : WindowModal("openmw_chargen_create_class.layout") , mSpecDialog(NULL) , mAttribDialog(NULL) , mSkillDialog(NULL) @@ -540,7 +540,7 @@ void CreateClassDialog::onDialogCancel() void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) { delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(*MWBase::Environment::get().getWindowManager()); + mSpecDialog = new SelectSpecializationDialog(); mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); mSpecDialog->setVisible(true); @@ -571,7 +571,7 @@ void CreateClassDialog::setSpecialization(int id) void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager()); + mAttribDialog = new SelectAttributeDialog(); mAffectedAttribute = _sender; mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); @@ -601,7 +601,7 @@ void CreateClassDialog::onAttributeSelected() void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager()); + mSkillDialog = new SelectSkillDialog(); mAffectedSkill = _sender; mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); @@ -633,7 +633,7 @@ void CreateClassDialog::onSkillSelected() void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) { - mDescDialog = new DescriptionDialog(*MWBase::Environment::get().getWindowManager()); + mDescDialog = new DescriptionDialog(); mDescDialog->setTextInput(mDescription); mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); mDescDialog->setVisible(true); @@ -660,8 +660,8 @@ void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) /* SelectSpecializationDialog */ -SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_specialization.layout", parWindowManager) +SelectSpecializationDialog::SelectSpecializationDialog() + : WindowModal("openmw_chargen_select_specialization.layout") { // Centre dialog center(); @@ -720,8 +720,8 @@ void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) /* SelectAttributeDialog */ -SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_attribute.layout", parWindowManager) +SelectAttributeDialog::SelectAttributeDialog() + : WindowModal("openmw_chargen_select_attribute.layout") { // Centre dialog center(); @@ -766,8 +766,8 @@ void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) /* SelectSkillDialog */ -SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_skill.layout", parWindowManager) +SelectSkillDialog::SelectSkillDialog() + : WindowModal("openmw_chargen_select_skill.layout") { // Centre dialog center(); @@ -856,8 +856,8 @@ void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) /* DescriptionDialog */ -DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_class_description.layout", parWindowManager) +DescriptionDialog::DescriptionDialog() + : WindowModal("openmw_chargen_class_description.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 11da1a791..15fc89658 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -15,7 +15,7 @@ namespace MWGui class InfoBoxDialog : public WindowModal { public: - InfoBoxDialog(MWBase::WindowManager& parWindowManager); + InfoBoxDialog(); typedef std::vector ButtonList; @@ -60,13 +60,13 @@ namespace MWGui Class_Create = 2, Class_Back = 3 }; - ClassChoiceDialog(MWBase::WindowManager& parWindowManager); + ClassChoiceDialog(); }; class GenerateClassResultDialog : public WindowModal { public: - GenerateClassResultDialog(MWBase::WindowManager& parWindowManager); + GenerateClassResultDialog(); std::string getClassId() const; void setClassId(const std::string &classId); @@ -93,7 +93,7 @@ namespace MWGui class PickClassDialog : public WindowModal { public: - PickClassDialog(MWBase::WindowManager& parWindowManager); + PickClassDialog(); const std::string &getClassId() const { return mCurrentClassId; } void setClassId(const std::string &classId); @@ -132,7 +132,7 @@ namespace MWGui class SelectSpecializationDialog : public WindowModal { public: - SelectSpecializationDialog(MWBase::WindowManager& parWindowManager); + SelectSpecializationDialog(); ~SelectSpecializationDialog(); ESM::Class::Specialization getSpecializationId() const { return mSpecializationId; } @@ -163,7 +163,7 @@ namespace MWGui class SelectAttributeDialog : public WindowModal { public: - SelectAttributeDialog(MWBase::WindowManager& parWindowManager); + SelectAttributeDialog(); ~SelectAttributeDialog(); ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; } @@ -192,7 +192,7 @@ namespace MWGui class SelectSkillDialog : public WindowModal { public: - SelectSkillDialog(MWBase::WindowManager& parWindowManager); + SelectSkillDialog(); ~SelectSkillDialog(); ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } @@ -225,7 +225,7 @@ namespace MWGui class DescriptionDialog : public WindowModal { public: - DescriptionDialog(MWBase::WindowManager& parWindowManager); + DescriptionDialog(); ~DescriptionDialog(); std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } @@ -241,7 +241,7 @@ namespace MWGui class CreateClassDialog : public WindowModal { public: - CreateClassDialog(MWBase::WindowManager& parWindowManager); + CreateClassDialog(); virtual ~CreateClassDialog(); std::string getName() const; diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 643cdf4c6..0a20c471a 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -13,9 +13,9 @@ namespace MWGui { -CompanionWindow::CompanionWindow(MWBase::WindowManager &parWindowManager, DragAndDrop *dragAndDrop, MessageBoxManager* manager) +CompanionWindow::CompanionWindow(DragAndDrop *dragAndDrop, MessageBoxManager* manager) : ContainerBase(dragAndDrop) - , WindowBase("openmw_companion_window.layout", parWindowManager) + , WindowBase("openmw_companion_window.layout") , mMessageBoxManager(manager) { MyGUI::ScrollView* itemView; diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 1b64a34d5..073a77a91 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -11,7 +11,7 @@ namespace MWGui class CompanionWindow : public ContainerBase, public WindowBase { public: - CompanionWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop, MessageBoxManager* manager); + CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); virtual ~CompanionWindow() {} void open(MWWorld::Ptr npc); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 31f4989e0..904468f88 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -7,8 +7,8 @@ namespace MWGui { - ConfirmationDialog::ConfirmationDialog(MWBase::WindowManager& parWindowManager) : - WindowModal("openmw_confirmation_dialog.layout", parWindowManager) + ConfirmationDialog::ConfirmationDialog() : + WindowModal("openmw_confirmation_dialog.layout") { getWidget(mMessage, "Message"); getWidget(mOkButton, "OkButton"); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index a925cad55..47b256017 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -8,7 +8,7 @@ namespace MWGui class ConfirmationDialog : public WindowModal { public: - ConfirmationDialog(MWBase::WindowManager& parWindowManager); + ConfirmationDialog(); void open(const std::string& message); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index f7846e70e..8ee4754a3 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -649,9 +649,9 @@ MWWorld::ContainerStore& ContainerBase::getContainerStore() // ------------------------------------------------------------------------------------------------ -ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop) +ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) - , WindowBase("openmw_container_window.layout", parWindowManager) + , WindowBase("openmw_container_window.layout") { getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mTakeButton, "TakeButton"); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 7a3e804e5..521ac8cc3 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -134,7 +134,7 @@ namespace MWGui class ContainerWindow : public ContainerBase, public WindowBase { public: - ContainerWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + ContainerWindow(DragAndDrop* dragAndDrop); virtual ~ContainerWindow(); diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 61c3c358a..d017cc198 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -7,8 +7,8 @@ namespace MWGui { - CountDialog::CountDialog(MWBase::WindowManager& parWindowManager) : - WindowModal("openmw_count_window.layout", parWindowManager) + CountDialog::CountDialog() : + WindowModal("openmw_count_window.layout") { getWidget(mSlider, "CountSlider"); getWidget(mItemEdit, "ItemEdit"); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index d5155839d..9d6d8b263 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -8,7 +8,7 @@ namespace MWGui class CountDialog : public WindowModal { public: - CountDialog(MWBase::WindowManager& parWindowManager); + CountDialog(); void open(const std::string& item, const std::string& message, const int maxCount); typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0939da1b1..f3c11752e 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -55,8 +55,8 @@ bool sortByLength (const std::string& left, const std::string& right) -PersuasionDialog::PersuasionDialog(MWBase::WindowManager &parWindowManager) - : WindowModal("openmw_persuasion_dialog.layout", parWindowManager) +PersuasionDialog::PersuasionDialog() + : WindowModal("openmw_persuasion_dialog.layout") { getWidget(mCancelButton, "CancelButton"); getWidget(mAdmireButton, "AdmireButton"); @@ -124,9 +124,9 @@ void PersuasionDialog::open() // -------------------------------------------------------------------------------------------------- -DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_dialogue_window.layout", parWindowManager) - , mPersuasionDialog(parWindowManager) +DialogueWindow::DialogueWindow() + : WindowBase("openmw_dialogue_window.layout") + , mPersuasionDialog() , mEnabled(false) , mServices(0) { diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index e78856c95..a1bbee02c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -29,7 +29,7 @@ namespace MWGui class PersuasionDialog : public WindowModal { public: - PersuasionDialog(MWBase::WindowManager& parWindowManager); + PersuasionDialog(); virtual void open(); @@ -50,7 +50,7 @@ namespace MWGui class DialogueWindow: public WindowBase, public ReferenceInterface { public: - DialogueWindow(MWBase::WindowManager& parWindowManager); + DialogueWindow(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 02d847d1a..2ae98f358 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -15,9 +15,9 @@ namespace MWGui { - EnchantingDialog::EnchantingDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) - , EffectEditorBase(parWindowManager) + EnchantingDialog::EnchantingDialog() + : WindowBase("openmw_enchanting_dialog.layout") + , EffectEditorBase() , mItemSelectionDialog(NULL) { getWidget(mName, "NameEdit"); @@ -139,7 +139,7 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}", - ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, *MWBase::Environment::get().getWindowManager()); + ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); @@ -227,7 +227,7 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}", - ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, *MWBase::Environment::get().getWindowManager()); + ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 822199ac6..c727a0974 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -17,7 +17,7 @@ namespace MWGui class EnchantingDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { public: - EnchantingDialog(MWBase::WindowManager& parWindowManager); + EnchantingDialog(); virtual ~EnchantingDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 393f03a54..dc7ef77ff 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -30,9 +30,9 @@ namespace MWGui { - InventoryWindow::InventoryWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop) + InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) - , WindowPinnableBase("openmw_inventory_window.layout", parWindowManager) + , WindowPinnableBase("openmw_inventory_window.layout") , mTrading(false) , mLastXSize(0) , mLastYSize(0) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 61ee17ef9..a4ed89d40 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -12,7 +12,7 @@ namespace MWGui class InventoryWindow : public ContainerBase, public WindowPinnableBase { public: - InventoryWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + InventoryWindow(DragAndDrop* dragAndDrop); virtual void open(); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 4b8adcef4..ed8b47b08 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -3,9 +3,9 @@ namespace MWGui { - ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter, MWBase::WindowManager& parWindowManager) + ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter) : ContainerBase(NULL) - , WindowModal("openmw_itemselection_dialog.layout", parWindowManager) + , WindowModal("openmw_itemselection_dialog.layout") { mFilter = filter; diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 733daa91a..3e812d26c 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -8,7 +8,7 @@ namespace MWGui class ItemSelectionDialog : public ContainerBase, public WindowModal { public: - ItemSelectionDialog(const std::string& label, int filter, MWBase::WindowManager& parWindowManager); + ItemSelectionDialog(const std::string& label, int filter); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index ba39b0101..a3198d6bc 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -81,8 +81,8 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) } -MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_journal.layout", parWindowManager) +MWGui::JournalWindow::JournalWindow () + : WindowBase("openmw_journal.layout") , mPageNumber(0) { mMainWidget->setVisible(false); diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 73a2dca2e..7670b65f5 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -14,7 +14,7 @@ namespace MWGui class JournalWindow : public WindowBase { public: - JournalWindow(MWBase::WindowManager& parWindowManager); + JournalWindow(); virtual void open(); virtual void close(); diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index dcecdccc1..fc1317e90 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -18,8 +18,8 @@ namespace MWGui { - LevelupDialog::LevelupDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_levelup_dialog.layout", parWindowManager) + LevelupDialog::LevelupDialog() + : WindowBase("openmw_levelup_dialog.layout") { getWidget(mOkButton, "OkButton"); getWidget(mClassImage, "ClassImage"); diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index a54948e2a..69afbf089 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui class LevelupDialog : public WindowBase { public: - LevelupDialog(MWBase::WindowManager& parWindowManager); + LevelupDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 306670512..858c3f36e 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -23,10 +23,10 @@ namespace MWGui { - LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw, MWBase::WindowManager& parWindowManager) + LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw) : mSceneMgr(sceneMgr) , mWindow(rw) - , WindowBase("openmw_loading_screen.layout", parWindowManager) + , WindowBase("openmw_loading_screen.layout") , mLoadingOn(false) , mLastRenderTime(0.f) , mLastWallpaperChangeTime(0.f) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index cb33975ae..12e6504bc 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -11,7 +11,7 @@ namespace MWGui class LoadingScreen : public WindowBase { public: - LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw, MWBase::WindowManager& parWindowManager); + LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw); virtual ~LoadingScreen(); void setLoadingProgress (const std::string& stage, int depth, int current, int total); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 029974d2b..17834be93 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -262,8 +262,8 @@ void LocalMapBase::setPlayerDir(const float x, const float y) // ------------------------------------------------------------------------------------------ -MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) +MapWindow::MapWindow(const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout") , mGlobal(false) { setCoord(500,0,320,300); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 329854e18..18c81a060 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -65,7 +65,7 @@ namespace MWGui class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase { public: - MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); + MapWindow(const std::string& cacheDir); virtual ~MapWindow(); void setCellName(const std::string& cellName); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index f24d2d417..53148cb3f 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -19,8 +19,8 @@ namespace MWGui { -MerchantRepair::MerchantRepair(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_merchantrepair.layout", parWindowManager) +MerchantRepair::MerchantRepair() + : WindowBase("openmw_merchantrepair.layout") { getWidget(mList, "RepairView"); getWidget(mOkButton, "OkButton"); diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 2cd6c486a..4cb39fe01 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -12,7 +12,7 @@ namespace MWGui class MerchantRepair : public WindowBase { public: - MerchantRepair(MWBase::WindowManager &parWindowManager); + MerchantRepair(); virtual void open(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 58bbc3c3a..8e53380bd 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -7,7 +7,7 @@ using namespace MWGui; -MessageBoxManager::MessageBoxManager (MWBase::WindowManager* windowManager) +MessageBoxManager::MessageBoxManager () { // defines mMessageBoxSpeed = 0.1; @@ -212,7 +212,7 @@ int MessageBox::getHeight () InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : WindowModal("openmw_interactive_messagebox.layout", *MWBase::Environment::get().getWindowManager()) + : WindowModal("openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index c64953b66..cb4073902 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -31,7 +31,7 @@ namespace MWGui class MessageBoxManager { public: - MessageBoxManager (MWBase::WindowManager* windowManager); + MessageBoxManager (); void onFrame (float frameDuration); void createMessageBox (const std::string& message); bool createInteractiveMessageBox (const std::string& message, const std::vector& buttons); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 82835a805..2deb37d30 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -43,8 +43,8 @@ namespace namespace MWGui { - QuickKeysMenu::QuickKeysMenu(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_quickkeys_menu.layout", parWindowManager) + QuickKeysMenu::QuickKeysMenu() + : WindowBase("openmw_quickkeys_menu.layout") , mAssignDialog(0) , mItemSelectionDialog(0) , mMagicSelectionDialog(0) @@ -109,7 +109,7 @@ namespace MWGui { // open assign dialog if (!mAssignDialog) - mAssignDialog = new QuickKeysMenuAssign(*MWBase::Environment::get().getWindowManager(), this); + mAssignDialog = new QuickKeysMenuAssign(this); mAssignDialog->setVisible (true); } } @@ -124,7 +124,7 @@ namespace MWGui { if (!mItemSelectionDialog ) { - mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, *MWBase::Environment::get().getWindowManager()); + mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItem); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } @@ -139,7 +139,7 @@ namespace MWGui { if (!mMagicSelectionDialog ) { - mMagicSelectionDialog = new MagicSelectionDialog(*MWBase::Environment::get().getWindowManager(), this); + mMagicSelectionDialog = new MagicSelectionDialog(this); } mMagicSelectionDialog->setVisible(true); @@ -352,8 +352,8 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - QuickKeysMenuAssign::QuickKeysMenuAssign (MWBase::WindowManager &parWindowManager, QuickKeysMenu* parent) - : WindowModal("openmw_quickkeys_menu_assign.layout", parWindowManager) + QuickKeysMenuAssign::QuickKeysMenuAssign (QuickKeysMenu* parent) + : WindowModal("openmw_quickkeys_menu_assign.layout") , mParent(parent) { getWidget(mLabel, "Label"); @@ -399,8 +399,8 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - MagicSelectionDialog::MagicSelectionDialog(MWBase::WindowManager &parWindowManager, QuickKeysMenu* parent) - : WindowModal("openmw_magicselection_dialog.layout", parWindowManager) + MagicSelectionDialog::MagicSelectionDialog(QuickKeysMenu* parent) + : WindowModal("openmw_magicselection_dialog.layout") , mParent(parent) , mWidth(0) , mHeight(0) diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index d5b6e6cd8..646ec2aa4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -16,7 +16,7 @@ namespace MWGui class QuickKeysMenu : public WindowBase { public: - QuickKeysMenu(MWBase::WindowManager& parWindowManager); + QuickKeysMenu(); ~QuickKeysMenu(); @@ -64,7 +64,7 @@ namespace MWGui class QuickKeysMenuAssign : public WindowModal { public: - QuickKeysMenuAssign(MWBase::WindowManager& parWindowManager, QuickKeysMenu* parent); + QuickKeysMenuAssign(QuickKeysMenu* parent); private: MyGUI::TextBox* mLabel; @@ -79,7 +79,7 @@ namespace MWGui class MagicSelectionDialog : public WindowModal { public: - MagicSelectionDialog(MWBase::WindowManager& parWindowManager, QuickKeysMenu* parent); + MagicSelectionDialog(QuickKeysMenu* parent); virtual void open(); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 167ad573a..9a0d8a029 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -62,8 +62,8 @@ int countParts(const std::string &part, const std::string &race, bool male) } } -RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_race.layout", parWindowManager) +RaceDialog::RaceDialog() + : WindowModal("openmw_chargen_race.layout") , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 4a4acd011..f3adce444 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -26,7 +26,7 @@ namespace MWGui class RaceDialog : public WindowModal { public: - RaceDialog(MWBase::WindowManager& parWindowManager); + RaceDialog(); enum Gender { diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 43c262ad8..0bd4b0995 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -15,8 +15,8 @@ namespace MWGui { -Repair::Repair(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_repair.layout", parWindowManager) +Repair::Repair() + : WindowBase("openmw_repair.layout") { getWidget(mRepairBox, "RepairBox"); getWidget(mRepairView, "RepairView"); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 824e0b6d2..5d9a48719 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -12,7 +12,7 @@ namespace MWGui class Repair : public WindowBase { public: - Repair(MWBase::WindowManager &parWindowManager); + Repair(); virtual void open(); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 74b189345..562bf9774 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -22,8 +22,8 @@ using namespace Widgets; const int ReviewDialog::sLineHeight = 18; -ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_review.layout", parWindowManager) +ReviewDialog::ReviewDialog() + : WindowModal("openmw_chargen_review.layout") , mLastPos(0) { // Centre dialog diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 9775a52de..d5df94e28 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -28,7 +28,7 @@ namespace MWGui }; typedef std::vector SkillList; - ReviewDialog(MWBase::WindowManager& parWindowManager); + ReviewDialog(); void setPlayerName(const std::string &name); void setRace(const std::string &raceId); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 22884bfe6..1935f7a9b 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,8 +12,8 @@ using namespace MWGui; -ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_scroll.layout", parWindowManager) +ScrollWindow::ScrollWindow () + : WindowBase("openmw_scroll.layout") , mTakeButtonShow(true) , mTakeButtonAllowed(true) { diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 59b39cab3..5feaff7bf 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -11,7 +11,7 @@ namespace MWGui class ScrollWindow : public WindowBase { public: - ScrollWindow (MWBase::WindowManager& parWindowManager); + ScrollWindow (); void open (MWWorld::Ptr scroll); void setTakeButtonShow(bool show); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index e21d4f589..c3718c260 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -93,8 +93,8 @@ namespace namespace MWGui { - SettingsWindow::SettingsWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_settings_window.layout", parWindowManager) + SettingsWindow::SettingsWindow() : + WindowBase("openmw_settings_window.layout") { getWidget(mOkButton, "OkButton"); getWidget(mSubtitlesButton, "SubtitlesButton"); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 292c1233d..6dcef2422 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -13,7 +13,7 @@ namespace MWGui class SettingsWindow : public WindowBase { public: - SettingsWindow(MWBase::WindowManager& parWindowManager); + SettingsWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9aa8074a2..7d634df8d 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -23,8 +23,8 @@ namespace MWGui { const int SpellBuyingWindow::sLineHeight = 18; - SpellBuyingWindow::SpellBuyingWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_spell_buying_window.layout", parWindowManager) + SpellBuyingWindow::SpellBuyingWindow() : + WindowBase("openmw_spell_buying_window.layout") , mCurrentY(0) , mLastPos(0) { diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 1418a9db5..f7ea54c89 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -21,7 +21,7 @@ namespace MWGui class SpellBuyingWindow : public ReferenceInterface, public WindowBase { public: - SpellBuyingWindow(MWBase::WindowManager& parWindowManager); + SpellBuyingWindow(); void startSpellBuying(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6fef91457..e1df9f9cd 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -40,8 +40,8 @@ namespace namespace MWGui { - EditEffectDialog::EditEffectDialog(MWBase::WindowManager &parWindowManager) - : WindowModal("openmw_edit_effect.layout", parWindowManager) + EditEffectDialog::EditEffectDialog() + : WindowModal("openmw_edit_effect.layout") , mEditing(false) { getWidget(mCancelButton, "CancelButton"); @@ -274,9 +274,9 @@ namespace MWGui // ------------------------------------------------------------------------------------------------ - SpellCreationDialog::SpellCreationDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_spellcreation_dialog.layout", parWindowManager) - , EffectEditorBase(parWindowManager) + SpellCreationDialog::SpellCreationDialog() + : WindowBase("openmw_spellcreation_dialog.layout") + , EffectEditorBase() { getWidget(mNameEdit, "NameEdit"); getWidget(mMagickaCost, "MagickaCost"); @@ -412,8 +412,8 @@ namespace MWGui // ------------------------------------------------------------------------------------------------ - EffectEditorBase::EffectEditorBase(MWBase::WindowManager& parWindowManager) - : mAddEffectDialog(parWindowManager) + EffectEditorBase::EffectEditorBase() + : mAddEffectDialog() , mSelectAttributeDialog(NULL) , mSelectSkillDialog(NULL) { @@ -541,7 +541,7 @@ namespace MWGui if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) { delete mSelectSkillDialog; - mSelectSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager ()); + mSelectSkillDialog = new SelectSkillDialog(); mSelectSkillDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel); mSelectSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectSkill); mSelectSkillDialog->setVisible (true); @@ -549,7 +549,7 @@ namespace MWGui else if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) { delete mSelectAttributeDialog; - mSelectAttributeDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager ()); + mSelectAttributeDialog = new SelectAttributeDialog(); mSelectAttributeDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel); mSelectAttributeDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectAttribute); mSelectAttributeDialog->setVisible (true); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index facbdf530..5ad306fbe 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -15,7 +15,7 @@ namespace MWGui class EditEffectDialog : public WindowModal { public: - EditEffectDialog(MWBase::WindowManager& parWindowManager); + EditEffectDialog(); virtual void open(); @@ -83,7 +83,7 @@ namespace MWGui class EffectEditorBase { public: - EffectEditorBase(MWBase::WindowManager& parWindowManager); + EffectEditorBase(); protected: @@ -123,7 +123,7 @@ namespace MWGui class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { public: - SpellCreationDialog(MWBase::WindowManager& parWindowManager); + SpellCreationDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 257fab89d..d07f9ca54 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -47,8 +47,8 @@ namespace namespace MWGui { - SpellWindow::SpellWindow(MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_spell_window.layout", parWindowManager) + SpellWindow::SpellWindow() + : WindowPinnableBase("openmw_spell_window.layout") , mHeight(0) , mWidth(0) { diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index b0994c590..521e73d76 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -10,7 +10,7 @@ namespace MWGui class SpellWindow : public WindowPinnableBase { public: - SpellWindow(MWBase::WindowManager& parWindowManager); + SpellWindow(); virtual ~SpellWindow(); void updateSpells(); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 0e0676c2f..a00ec167d 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -22,8 +22,8 @@ using namespace MWGui; const int StatsWindow::sLineHeight = 18; -StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) +StatsWindow::StatsWindow () + : WindowPinnableBase("openmw_stats_window.layout") , mSkillView(NULL) , mClientHeight(0) , mMajorSkills() diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 93e26e063..4b723048c 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -22,7 +22,7 @@ namespace MWGui typedef std::vector SkillList; - StatsWindow(MWBase::WindowManager& parWindowManager); + StatsWindow(); /// automatically updates all the data in the stats window, but only if it has changed. void onFrame(); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 071971bef..ab2936cfc 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -5,8 +5,8 @@ using namespace MWGui; -TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_text_input.layout", parWindowManager) +TextInputDialog::TextInputDialog() + : WindowModal("openmw_text_input.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index 6b371bae7..1f53263ec 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -13,7 +13,7 @@ namespace MWGui class TextInputDialog : public WindowModal { public: - TextInputDialog(MWBase::WindowManager& parWindowManager); + TextInputDialog(); std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7730019e8..2250ffd0b 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -19,7 +19,7 @@ using namespace MWGui; using namespace MyGUI; -ToolTips::ToolTips(MWBase::WindowManager* windowManager) : +ToolTips::ToolTips() : Layout("openmw_tooltips.layout") , mGameMode(true) , mFullHelp(false) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index e4fcb310c..f8f256167 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -39,7 +39,7 @@ namespace MWGui class ToolTips : public OEngine::GUI::Layout { public: - ToolTips(MWBase::WindowManager* windowManager); + ToolTips(); void onFrame(float frameDuration); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 718e6378b..718f40c78 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -24,8 +24,8 @@ namespace MWGui const float TradeWindow::sBalanceChangeInitialPause = 0.5; const float TradeWindow::sBalanceChangeInterval = 0.1; - TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_trade_window.layout", parWindowManager) + TradeWindow::TradeWindow() : + WindowBase("openmw_trade_window.layout") , ContainerBase(NULL) // no drag&drop , mCurrentBalance(0) , mBalanceButtonsState(BBS_None) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 111c0935f..e526a42ca 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -23,7 +23,7 @@ namespace MWGui class TradeWindow : public ContainerBase, public WindowBase { public: - TradeWindow(MWBase::WindowManager& parWindowManager); + TradeWindow(); void startTrade(MWWorld::Ptr actor); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index c2b543a4f..f85a8be59 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -20,8 +20,8 @@ namespace MWGui { - TrainingWindow::TrainingWindow(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_trainingwindow.layout", parWindowManager) + TrainingWindow::TrainingWindow() + : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) { getWidget(mTrainingOptions, "TrainingOptions"); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index d6be60ae6..740115cdf 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -10,7 +10,7 @@ namespace MWGui class TrainingWindow : public WindowBase, public ReferenceInterface { public: - TrainingWindow(MWBase::WindowManager& parWindowManager); + TrainingWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index b71017166..0a74c921a 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -25,8 +25,8 @@ namespace MWGui { const int TravelWindow::sLineHeight = 18; - TravelWindow::TravelWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_travel_window.layout", parWindowManager) + TravelWindow::TravelWindow() : + WindowBase("openmw_travel_window.layout") , mCurrentY(0) , mLastPos(0) { diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 61b724910..a814d0478 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -23,7 +23,7 @@ namespace MWGui class TravelWindow : public ReferenceInterface, public WindowBase { public: - TravelWindow(MWBase::WindowManager& parWindowManager); + TravelWindow(); void startTravel(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 69dfa10b4..a84b9203a 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -25,8 +25,8 @@ namespace MWGui { - WaitDialogProgressBar::WaitDialogProgressBar(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_wait_dialog_progressbar.layout", parWindowManager) + WaitDialogProgressBar::WaitDialogProgressBar() + : WindowBase("openmw_wait_dialog_progressbar.layout") { getWidget(mProgressBar, "ProgressBar"); getWidget(mProgressText, "ProgressText"); @@ -46,9 +46,9 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - WaitDialog::WaitDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_wait_dialog.layout", parWindowManager) - , mProgressBar(parWindowManager) + WaitDialog::WaitDialog() + : WindowBase("openmw_wait_dialog.layout") + , mProgressBar() , mWaiting(false) , mSleeping(false) , mHours(1) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 4510e665b..d06d7d112 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui class WaitDialogProgressBar : public WindowBase { public: - WaitDialogProgressBar(MWBase::WindowManager& parWindowManager); + WaitDialogProgressBar(); virtual void open(); @@ -23,7 +23,7 @@ namespace MWGui class WaitDialog : public WindowBase { public: - WaitDialog(MWBase::WindowManager& parWindowManager); + WaitDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 3801ae6f7..dd3206ed6 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -34,8 +34,7 @@ void MWGui::Widgets::fixTexturePath(std::string &path) /* MWSkill */ MWSkill::MWSkill() - : mManager(NULL) - , mSkillId(ESM::Skill::Length) + : mSkillId(ESM::Skill::Length) , mSkillNameWidget(NULL) , mSkillValueWidget(NULL) { @@ -65,7 +64,7 @@ void MWSkill::setSkillValue(const SkillValue& value) void MWSkill::updateWidgets() { - if (mSkillNameWidget && mManager) + if (mSkillNameWidget) { if (mSkillId == ESM::Skill::Length) { @@ -73,7 +72,7 @@ void MWSkill::updateWidgets() } else { - const std::string &name = mManager->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); static_cast(mSkillNameWidget)->setCaption(name); } } @@ -126,8 +125,7 @@ void MWSkill::initialiseOverride() /* MWAttribute */ MWAttribute::MWAttribute() - : mManager(NULL) - , mId(-1) + : mId(-1) , mAttributeNameWidget(NULL) , mAttributeValueWidget(NULL) { @@ -152,7 +150,7 @@ void MWAttribute::onClicked(MyGUI::Widget* _sender) void MWAttribute::updateWidgets() { - if (mAttributeNameWidget && mManager) + if (mAttributeNameWidget) { if (mId < 0 || mId >= 8) { @@ -170,7 +168,7 @@ void MWAttribute::updateWidgets() "sAttributePersonality", "sAttributeLuck" }; - const std::string &name = mManager->getGameSettingString(attributes[mId], ""); + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); static_cast(mAttributeNameWidget)->setCaption(name); } } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 26ca75066..038ce3f86 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -98,7 +98,6 @@ namespace MWGui void setSkillNumber(int skillId); void setSkillValue(const SkillValue& value); - MWBase::WindowManager *getWindowManager() const { return mManager; } ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } const SkillValue& getSkillValue() const { return mValue; } @@ -121,7 +120,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager *mManager; ESM::Skill::SkillEnum mSkillId; SkillValue mValue; MyGUI::Widget* mSkillNameWidget; @@ -140,7 +138,6 @@ namespace MWGui void setAttributeId(int attributeId); void setAttributeValue(const AttributeValue& value); - MWBase::WindowManager *getWindowManager() const { return mManager; } int getAttributeId() const { return mId; } const AttributeValue& getAttributeValue() const { return mValue; } @@ -163,7 +160,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager *mManager; int mId; AttributeValue mValue; MyGUI::Widget* mAttributeNameWidget; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index cb3d4ea8c..c41bcb7ce 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -6,7 +6,7 @@ using namespace MWGui; -WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) +WindowBase::WindowBase(const std::string& parLayout) : Layout(parLayout) { } @@ -38,8 +38,8 @@ void WindowBase::center() mMainWidget->setCoord(coord); } -WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager) +WindowModal::WindowModal(const std::string& parLayout) + : WindowBase(parLayout) { } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index a2cb731fe..2c014baf0 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -15,7 +15,7 @@ namespace MWGui class WindowBase: public OEngine::GUI::Layout { public: - WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowBase(const std::string& parLayout); // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; @@ -38,7 +38,7 @@ namespace MWGui class WindowModal : public WindowBase { public: - WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowModal(const std::string& parLayout); virtual void open(); virtual void close(); }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bcde82e96..f2ded8813 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -162,38 +162,38 @@ WindowManager::WindowManager( mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; mMenu = new MainMenu(w,h); - mMap = new MapWindow(*this, cacheDir); - mStatsWindow = new StatsWindow(*this); + mMap = new MapWindow(cacheDir); + mStatsWindow = new StatsWindow(); mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(*this); - mMessageBoxManager = new MessageBoxManager(this); - mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); - mTradeWindow = new TradeWindow(*this); - mSpellBuyingWindow = new SpellBuyingWindow(*this); - mTravelWindow = new TravelWindow(*this); - mDialogueWindow = new DialogueWindow(*this); - mContainerWindow = new ContainerWindow(*this,mDragAndDrop); + mJournal = new JournalWindow(); + mMessageBoxManager = new MessageBoxManager(); + mInventoryWindow = new InventoryWindow(mDragAndDrop); + mTradeWindow = new TradeWindow(); + mSpellBuyingWindow = new SpellBuyingWindow(); + mTravelWindow = new TravelWindow(); + mDialogueWindow = new DialogueWindow(); + mContainerWindow = new ContainerWindow(mDragAndDrop); mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); - mToolTips = new ToolTips(this); - mScrollWindow = new ScrollWindow(*this); - mBookWindow = new BookWindow(*this); - mCountDialog = new CountDialog(*this); - mSettingsWindow = new SettingsWindow(*this); - mConfirmationDialog = new ConfirmationDialog(*this); - mAlchemyWindow = new AlchemyWindow(*this); - mSpellWindow = new SpellWindow(*this); - mQuickKeysMenu = new QuickKeysMenu(*this); - mLevelupDialog = new LevelupDialog(*this); - mWaitDialog = new WaitDialog(*this); - mSpellCreationDialog = new SpellCreationDialog(*this); - mEnchantingDialog = new EnchantingDialog(*this); - mTrainingWindow = new TrainingWindow(*this); - mMerchantRepair = new MerchantRepair(*this); - mRepair = new Repair(*this); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mBookWindow = new BookWindow(); + mCountDialog = new CountDialog(); + mSettingsWindow = new SettingsWindow(); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); + mSpellWindow = new SpellWindow(); + mQuickKeysMenu = new QuickKeysMenu(); + mLevelupDialog = new LevelupDialog(); + mWaitDialog = new WaitDialog(); + mSpellCreationDialog = new SpellCreationDialog(); + mEnchantingDialog = new EnchantingDialog(); + mTrainingWindow = new TrainingWindow(); + mMerchantRepair = new MerchantRepair(); + mRepair = new Repair(); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(*this, mDragAndDrop, mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); mLoadingScreen->onResChange (w,h); mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); @@ -202,7 +202,7 @@ WindowManager::WindowManager( mHud->setVisible(mHudEnabled); - mCharGen = new CharacterCreation(this); + mCharGen = new CharacterCreation(); // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 54ed082cf..56868306a 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -6,8 +6,8 @@ using namespace MWGui; -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) +WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) + : WindowBase(parLayout), mPinned(false), mVisible(false) { ExposedWindow* window = static_cast(mMainWidget); mPinButton = window->getSkinWidget ("Button"); diff --git a/apps/openmw/mwgui/windowpinnablebase.hpp b/apps/openmw/mwgui/windowpinnablebase.hpp index 657e8142f..1ab629432 100644 --- a/apps/openmw/mwgui/windowpinnablebase.hpp +++ b/apps/openmw/mwgui/windowpinnablebase.hpp @@ -10,7 +10,7 @@ namespace MWGui class WindowPinnableBase: public WindowBase { public: - WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowPinnableBase(const std::string& parLayout); bool pinned() { return mPinned; } private: From 3a87b12bafefd6b7f97c9a2ddac43fddc496d549 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 21:31:14 +0200 Subject: [PATCH 245/817] delete script subview on script deletion --- apps/opencs/view/world/scriptsubview.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 2fdb44aec..0319033b0 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -53,8 +53,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); -// connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int start, int end)), -// this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int start, int end))); + connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); } void CSVWorld::ScriptSubView::setEditLock (bool locked) @@ -88,5 +88,8 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) { + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + if (!parent.isValid() && index.row()>=start && index.row()<=end) + deleteLater(); } \ No newline at end of file From 6c6750342c321b537fcc7cc14246050fc4bf2580 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 13:37:20 -0700 Subject: [PATCH 246/817] Specified particle size is actually the radius --- components/nif/data.hpp | 4 ++-- components/nifogre/ogrenifloader.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index bd109041f..f1f34184b 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -167,7 +167,7 @@ class NiAutoNormalParticlesData : public ShapeData public: int numParticles; - float particleSize; + float particleRadius; int activeCount; @@ -180,7 +180,7 @@ public: // Should always match the number of vertices numParticles = nif->getUShort(); - particleSize = nif->getFloat(); + particleRadius = nif->getFloat(); activeCount = nif->getUShort(); if(nif->getInt()) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3c876283e..62732d387 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1543,7 +1543,8 @@ class NIFObjectLoader : Ogre::ManualResourceLoader vertprop, zprop, specprop, wireprop, needTangents)); - partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); + partsys->setDefaultDimensions(particledata->particleRadius*2.0f, + particledata->particleRadius*2.0f); partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); From 74145410f24d6c60b6cdca81aa14e40564691cda Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 22:49:22 +0200 Subject: [PATCH 247/817] basic syntax highlighting in script subview --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/world/scriptcontext.cpp | 22 ++++ apps/opencs/model/world/scriptcontext.hpp | 26 +++++ apps/opencs/view/world/scripthighlighter.cpp | 105 +++++++++++++++++++ apps/opencs/view/world/scripthighlighter.hpp | 77 ++++++++++++++ apps/opencs/view/world/scriptsubview.cpp | 4 + components/CMakeLists.txt | 2 +- components/compiler/nullerrorhandler.cpp | 6 ++ components/compiler/nullerrorhandler.hpp | 21 ++++ 9 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/world/scriptcontext.cpp create mode 100644 apps/opencs/model/world/scriptcontext.hpp create mode 100644 apps/opencs/view/world/scripthighlighter.cpp create mode 100644 apps/opencs/view/world/scripthighlighter.hpp create mode 100644 components/compiler/nullerrorhandler.cpp create mode 100644 components/compiler/nullerrorhandler.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bd882892f..5c15938bd 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -22,7 +22,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid data record idcollection commands columnbase + universalid data record idcollection commands columnbase scriptcontext ) opencs_hdrs_noqt (model/world @@ -59,7 +59,7 @@ opencs_units (view/world ) opencs_units_noqt (view/world - dialoguesubview util subviews enumdelegate vartypedelegate + dialoguesubview util subviews enumdelegate vartypedelegate scripthighlighter ) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp new file mode 100644 index 000000000..69b72abf2 --- /dev/null +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -0,0 +1,22 @@ + +#include "scriptcontext.hpp" + +bool CSMWorld::ScriptContext::canDeclareLocals() const +{ + return false; +} + +char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const +{ + return ' '; +} + +char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const +{ + return ' '; +} + +bool CSMWorld::ScriptContext::isId (const std::string& name) const +{ + return false; +} \ No newline at end of file diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp new file mode 100644 index 000000000..1231aea64 --- /dev/null +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_WORLD_SCRIPTCONTEXT_H +#define CSM_WORLD_SCRIPTCONTEXT_H + +#include + +namespace CSMWorld +{ + class ScriptContext : public Compiler::Context + { + public: + + virtual bool canDeclareLocals() const; + ///< Is the compiler allowed to declare local variables? + + virtual char getGlobalType (const std::string& name) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + + virtual char getMemberType (const std::string& name, const std::string& id) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + + virtual bool isId (const std::string& name) const; + ///< Does \a name match an ID, that can be referenced? + }; +} + +#endif diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp new file mode 100644 index 000000000..1e93ac26b --- /dev/null +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -0,0 +1,105 @@ + +#include "scripthighlighter.hpp" + +#include + +#include + +bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Int); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseFloat (float value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Float); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Name); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseKeyword (int keyword, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Keyword); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseSpecial (int code, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Special); + return true; +} + +void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner) +{} + +void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type type) +{ + int length = static_cast (loc.mLiteral.size()); + + int index = loc.mColumn; + + // compensate for bug in Compiler::Scanner (position of token is the character after the token) + index -= length; + + setFormat (index, length, mScheme[type]); +} + +CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) +: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext) +{ + /// \ŧodo replace this with user settings + { + QTextCharFormat format; + format.setForeground (Qt::darkMagenta); + mScheme.insert (std::make_pair (Type_Int, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::green); + mScheme.insert (std::make_pair (Type_Float, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::gray); + mScheme.insert (std::make_pair (Type_Name, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::red); + mScheme.insert (std::make_pair (Type_Keyword, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::darkYellow); + mScheme.insert (std::make_pair (Type_Special, format)); + } +} + +void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) +{ + std::istringstream stream (text.toUtf8().constData()); + + Compiler::Scanner scanner (mErrorHandler, stream, mContext.getExtensions()); + + try + { + scanner.scan (*this); + } + catch (...) {} // ignore syntax errors + +} \ No newline at end of file diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp new file mode 100644 index 000000000..e9918f99b --- /dev/null +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -0,0 +1,77 @@ +#ifndef CSV_WORLD_SCRIPTHIGHLIGHTER_H +#define CSV_WORLD_SCRIPTHIGHLIGHTER_H + +#include + +#include + +#include +#include + +#include "../../model/world/scriptcontext.hpp" + +namespace CSVWorld +{ + class ScriptHighlighter : public QSyntaxHighlighter, private Compiler::Parser + { + public: + + enum Type + { + Type_Int, + Type_Float, + Type_Name, + Type_Keyword, + Type_Special + }; + + private: + + Compiler::NullErrorHandler mErrorHandler; + CSMWorld::ScriptContext mContext; + std::map mScheme; + + private: + + virtual bool parseInt (int value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle an int token. + /// \return fetch another token? + + virtual bool parseFloat (float value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a float token. + /// \return fetch another token? + + virtual bool parseName (const std::string& name, + const Compiler::TokenLoc& loc, Compiler::Scanner& scanner); + ///< Handle a name token. + /// \return fetch another token? + + virtual bool parseKeyword (int keyword, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + + virtual bool parseSpecial (int code, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + ///< Handle a special character token. + /// \return fetch another token? + + virtual void parseEOF (Compiler::Scanner& scanner); + ///< Handle EOF token. + + void highlight (const Compiler::TokenLoc& loc, Type type); + + public: + + ScriptHighlighter (QTextDocument *parent); + + virtual void highlightBlock (const QString& text); + }; +} + +#endif diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0319033b0..ab1c2d57c 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -12,6 +12,8 @@ #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" +#include "scripthighlighter.hpp" + CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) { ++mView.mChangeLocked; @@ -55,6 +57,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); + + new ScriptHighlighter (mEditor->document()); } void CSVWorld::ScriptSubView::setEditLock (bool locked) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a2f416fcc..ed12ff2f0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -54,7 +54,7 @@ add_component_dir (files add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler - stringparser tokenloc + stringparser tokenloc nullerrorhandler ) add_component_dir (interpreter diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp new file mode 100644 index 000000000..3071701e8 --- /dev/null +++ b/components/compiler/nullerrorhandler.cpp @@ -0,0 +1,6 @@ + +#include "nullerrorhandler.hpp" + +void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} + +void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} \ No newline at end of file diff --git a/components/compiler/nullerrorhandler.hpp b/components/compiler/nullerrorhandler.hpp new file mode 100644 index 000000000..bb4db99a2 --- /dev/null +++ b/components/compiler/nullerrorhandler.hpp @@ -0,0 +1,21 @@ + +#ifndef COMPILER_NULLERRORHANDLER_H_INCLUDED +#define COMPILER_NULLERRORHANDLER_H_INCLUDED + +#include "errorhandler.hpp" + +namespace Compiler +{ + /// \brief Error handler implementation: Ignore all error messages + + class NullErrorHandler : public ErrorHandler + { + virtual void report (const std::string& message, const TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + }; +} + +#endif From 106ef4c9369e303aaf79654c597961e1516f3522 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 10 Apr 2013 22:53:03 +0200 Subject: [PATCH 248/817] Rotate script --- apps/openmw/mwscript/docs/vmformat.txt | 4 +- .../mwscript/transformationextensions.cpp | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7e9827062..7810c2874 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -318,5 +318,7 @@ op 0x20001fb: DropSoulGem, explicit reference op 0x20001fc: OnDeath op 0x20001fd: IsWerewolf op 0x20001fe: IsWerewolf, explicit reference +op 0x20001ff: Rotate +op 0x2000200: Rotate, explicit reference -opcodes 0x20001ff-0x3ffffff unused +opcodes 0x2000201-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 49688efb5..6c4fb0f4b 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -542,6 +542,42 @@ namespace MWScript } }; + template + class OpRotate : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why + runtime.pop(); + + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + + //Axis in morrowind are inverted + if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + } + else if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -568,6 +604,8 @@ namespace MWScript const int opcodePlaceAtMeExplicit = 0x200019e; const int opcodeModScale = 0x20001e3; const int opcodeModScaleExplicit = 0x20001e4; + const int opcodeRotate = 0x20001ff; + const int opcodeRotateExplicit = 0x2000200; void registerExtensions (Compiler::Extensions& extensions) { @@ -585,6 +623,7 @@ namespace MWScript extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); + extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -614,6 +653,8 @@ namespace MWScript interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); interpreter.installSegment5(opcodeModScale,new OpModScale); interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); + interpreter.installSegment5(opcodeRotate,new OpRotate); + interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); } } } From caff28e20acb914997143e51ac503835f3a8fb4d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 19:58:17 -0700 Subject: [PATCH 249/817] Move NIFSkeletonLoader to a separate file --- apps/openmw/mwrender/animation.hpp | 3 + components/CMakeLists.txt | 2 +- components/nifogre/ogrenifloader.cpp | 366 +-------------------------- components/nifogre/ogrenifloader.hpp | 4 +- components/nifogre/skeleton.cpp | 351 +++++++++++++++++++++++++ components/nifogre/skeleton.hpp | 63 +++++ 6 files changed, 421 insertions(+), 368 deletions(-) create mode 100644 components/nifogre/skeleton.cpp create mode 100644 components/nifogre/skeleton.hpp diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cfef28f16..029c56523 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,6 +1,9 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H +#include +#include + #include #include "../mwworld/ptr.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a2f416fcc..d43725ee0 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader + ogrenifloader skeleton ) add_component_dir (nifbullet diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 62732d387..0a30f38bd 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -51,7 +51,7 @@ #include #include -typedef unsigned char ubyte; +#include "skeleton.hpp" namespace std { @@ -424,370 +424,6 @@ public: }; -/** Manual resource loader for NIF skeletons. This is the main class - responsible for translating the internal NIF skeleton structure into - something Ogre can use (includes animations and node TextKeyData). - */ -class NIFSkeletonLoader : public Ogre::ManualResourceLoader -{ -static void warn(const std::string &msg) -{ - std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; -} - -static void fail(const std::string &msg) -{ - std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; - abort(); -} - - -static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) -{ - Ogre::Animation *anim = skel->createAnimation(name, stopTime); - - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *kfc = ctrls[i]; - if(kfc->data.empty()) - continue; - const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - - Ogre::Bone *bone = skel->getBone(targets[i]); - // NOTE: For some reason, Ogre doesn't like the node track ID being different from - // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? - anim->getNodeTrack(bone->getHandle()) : - anim->createNodeTrack(bone->getHandle(), bone); - - Ogre::Quaternion lastquat, curquat; - Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); - Ogre::Vector3 lastscale(1.0f), curscale(1.0f); - if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - - bool didlast = false; - while(!didlast) - { - float curtime = std::numeric_limits::max(); - - //Get latest time - if(quatiter != quatkeys.mKeys.end()) - curtime = std::min(curtime, quatiter->mTime); - if(traniter != trankeys.mKeys.end()) - curtime = std::min(curtime, traniter->mTime); - if(scaleiter != scalekeys.mKeys.end()) - curtime = std::min(curtime, scaleiter->mTime); - - curtime = std::max(curtime, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; - float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); - kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); - } - if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) - kframe->setTranslate(curtrans); - else - { - Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; - float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); - kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); - } - if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) - kframe->setScale(curscale); - else - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); -} - - -static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) -{ - TextKeyMap textkeys; - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - return textkeys; -} - -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) -{ - Ogre::Bone *bone; - if(!skel->hasBone(node->name)) - bone = skel->createBone(node->name); - else - bone = skel->createBone(); - if(parent) parent->addChild(bone); - mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); - - bone->setOrientation(node->trafo.rotation); - bone->setPosition(node->trafo.pos); - bone->setScale(Ogre::Vector3(node->trafo.scale)); - bone->setBindingPose(); - - if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ - node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ - node->recType == Nif::RC_NiCamera || - node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles - )) - warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController - )) - warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); - ctrl = ctrl->next; - } - - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - textkeys = extractTextKeys(tk); - animroot = bone; - } - e = e->extra; - } - - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); - } - } -} - -// Lookup to retrieve an Ogre bone handle for a given Nif record index -std::map mNifToOgreHandleMap; - -typedef std::map LoaderMap; -static LoaderMap sLoaders; - -public: -void loadResource(Ogre::Resource *resource) -{ - Ogre::Skeleton *skel = dynamic_cast(resource); - OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); - - Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); - const Nif::Node *node = static_cast(nif->getRoot(0)); - - std::vector ctrls; - Ogre::Bone *animroot = NULL; - TextKeyMap textkeys; - try { - buildBones(skel, node, animroot, textkeys, ctrls); - } - catch(std::exception &e) { - std::cerr<< "Exception while loading "<getName() < targets; - // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file - if(ctrls.size() == 0) // No animations? Then we're done. - return; - - float maxtime = 0.0f; - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *ctrl = ctrls[i]; - maxtime = std::max(maxtime, ctrl->timeStop); - Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); - if(target != NULL) - targets.push_back(target->name); - } - - if(targets.size() != ctrls.size()) - { - warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ - Ogre::StringConverter::toString(ctrls.size())+" controllers)"); - return; - } - - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); - bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); - - std::string currentgroup; - TextKeyMap::const_iterator keyiter = textkeys.begin(); - for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) - { - std::string::size_type sep = keyiter->second.find(':'); - if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || - (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) - continue; - currentgroup = keyiter->second.substr(0, sep); - - if(skel->hasAnimation(currentgroup)) - continue; - - TextKeyMap::const_iterator lastkeyiter = textkeys.end(); - while((--lastkeyiter)->first > keyiter->first) - { - if(lastkeyiter->second.find(':') == currentgroup.length() && - lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) - break; - } - - buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - - TextKeyMap::const_iterator insiter(keyiter); - TextKeyMap groupkeys; - do { - sep = insiter->second.find(':'); - if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); - else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first, insiter->second)); - } while(insiter++ != lastkeyiter); - - bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); - } -} - - -static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) -{ - /* We need to be a little aggressive here, since some NIFs have a crap-ton - * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: - * There are no bones used for skinning, there are no controllers on non- - * NiTriShape nodes, there are no nodes named "AttachLight", and the tree - * consists of NiNode, NiTriShape, and RootCollisionNode types only. - */ - if(!node->boneTrafo) - { - if(node->recType == Nif::RC_NiTriShape) - return Ogre::SkeletonPtr(); - if(node->controller.empty() && node->name != "AttachLight") - { - if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) - { - const Nif::NiNode *ninode = static_cast(node); - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); - if(!skel.isNull()) - return skel; - } - } - return Ogre::SkeletonPtr(); - } - } - } - - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - return skelMgr.create(name, group, true, &sLoaders[name]); -} - -// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be -// used when the bone name is insufficient as this is a relatively slow lookup -static int lookupOgreBoneHandle(const std::string &nifname, int idx) -{ - LoaderMap::const_iterator loader = sLoaders.find(nifname); - if(loader != sLoaders.end()) - { - std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); - if(entry != loader->second.mNifToOgreHandleMap.end()) - return entry->second; - } - throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); -} - -}; -NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; - - // Conversion of blend / test mode from NIF static const char *getBlendFactor(int mode) { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 18bbf0200..fa5182aea 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -25,11 +25,11 @@ #define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP #include -#include -#include +#include #include #include +#include // FIXME: This namespace really doesn't do anything Nif-specific. Any supportable diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp new file mode 100644 index 000000000..e97e91ef0 --- /dev/null +++ b/components/nifogre/skeleton.cpp @@ -0,0 +1,351 @@ +#include "skeleton.hpp" + +#include +#include +#include +#include + +#include +#include + +namespace NifOgre +{ + +void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) +{ + Ogre::Animation *anim = skel->createAnimation(name, stopTime); + + for(size_t i = 0;i < ctrls.size();i++) + { + const Nif::NiKeyframeController *kfc = ctrls[i]; + if(kfc->data.empty()) + continue; + const Nif::NiKeyframeData *kf = kfc->data.getPtr(); + + /* Get the keyframes and make sure they're sorted first to last */ + const Nif::QuaternionKeyList &quatkeys = kf->mRotations; + const Nif::Vector3KeyList &trankeys = kf->mTranslations; + const Nif::FloatKeyList &scalekeys = kf->mScales; + + Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + + Ogre::Bone *bone = skel->getBone(targets[i]); + // NOTE: For some reason, Ogre doesn't like the node track ID being different from + // the bone ID + Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? + anim->getNodeTrack(bone->getHandle()) : + anim->createNodeTrack(bone->getHandle(), bone); + + Ogre::Quaternion lastquat, curquat; + Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); + Ogre::Vector3 lastscale(1.0f), curscale(1.0f); + if(quatiter != quatkeys.mKeys.end()) + lastquat = curquat = quatiter->mValue; + if(traniter != trankeys.mKeys.end()) + lasttrans = curtrans = traniter->mValue; + if(scaleiter != scalekeys.mKeys.end()) + lastscale = curscale = Ogre::Vector3(scaleiter->mValue); + + bool didlast = false; + while(!didlast) + { + float curtime = std::numeric_limits::max(); + + //Get latest time + if(quatiter != quatkeys.mKeys.end()) + curtime = std::min(curtime, quatiter->mTime); + if(traniter != trankeys.mKeys.end()) + curtime = std::min(curtime, traniter->mTime); + if(scaleiter != scalekeys.mKeys.end()) + curtime = std::min(curtime, scaleiter->mTime); + + curtime = std::max(curtime, startTime); + if(curtime >= stopTime) + { + didlast = true; + curtime = stopTime; + } + + // Get the latest quaternions, translations, and scales for the + // current time + while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) + { + lastquat = curquat; + if(++quatiter != quatkeys.mKeys.end()) + curquat = quatiter->mValue; + } + while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) + { + lasttrans = curtrans; + if(++traniter != trankeys.mKeys.end()) + curtrans = traniter->mValue; + } + while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) + { + lastscale = curscale; + if(++scaleiter != scalekeys.mKeys.end()) + curscale = Ogre::Vector3(scaleiter->mValue); + } + + Ogre::TransformKeyFrame *kframe; + kframe = nodetrack->createNodeKeyFrame(curtime); + if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) + kframe->setRotation(curquat); + else + { + Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; + float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); + kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); + } + if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) + kframe->setTranslate(curtrans); + else + { + Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; + float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); + kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); + } + if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) + kframe->setScale(curscale); + else + { + Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; + float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); + kframe->setScale(lastscale + ((curscale-lastscale)*diff)); + } + } + } + anim->optimise(); +} + + +TextKeyMap NIFSkeletonLoader::extractTextKeys(const Nif::NiTextKeyExtraData *tk) +{ + TextKeyMap textkeys; + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + return textkeys; +} + +void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent) +{ + Ogre::Bone *bone; + if(!skel->hasBone(node->name)) + bone = skel->createBone(node->name); + else + bone = skel->createBone(); + if(parent) parent->addChild(bone); + mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); + + bone->setOrientation(node->trafo.rotation); + bone->setPosition(node->trafo.pos); + bone->setScale(Ogre::Vector3(node->trafo.scale)); + bone->setBindingPose(); + + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiCamera || + node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles + )) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiKeyframeController) + ctrls.push_back(static_cast(ctrl.getPtr())); + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController + )) + warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); + ctrl = ctrl->next; + } + + Nif::ExtraPtr e = node->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + textkeys = extractTextKeys(tk); + animroot = bone; + } + e = e->extra; + } + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); + } + } +} + +void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) +{ + Ogre::Skeleton *skel = dynamic_cast(resource); + OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); + + Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); + const Nif::Node *node = static_cast(nif->getRoot(0)); + + std::vector ctrls; + Ogre::Bone *animroot = NULL; + TextKeyMap textkeys; + try { + buildBones(skel, node, animroot, textkeys, ctrls); + } + catch(std::exception &e) { + std::cerr<< "Exception while loading "<getName() < targets; + // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file + if(ctrls.size() == 0) // No animations? Then we're done. + return; + + float maxtime = 0.0f; + for(size_t i = 0;i < ctrls.size();i++) + { + const Nif::NiKeyframeController *ctrl = ctrls[i]; + maxtime = std::max(maxtime, ctrl->timeStop); + Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); + if(target != NULL) + targets.push_back(target->name); + } + + if(targets.size() != ctrls.size()) + { + warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ + Ogre::StringConverter::toString(ctrls.size())+" controllers)"); + return; + } + + Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); + bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); + + std::string currentgroup; + TextKeyMap::const_iterator keyiter = textkeys.begin(); + for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) + { + std::string::size_type sep = keyiter->second.find(':'); + if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || + (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) + continue; + currentgroup = keyiter->second.substr(0, sep); + + if(skel->hasAnimation(currentgroup)) + continue; + + TextKeyMap::const_iterator lastkeyiter = textkeys.end(); + while((--lastkeyiter)->first > keyiter->first) + { + if(lastkeyiter->second.find(':') == currentgroup.length() && + lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) + break; + } + + buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + + TextKeyMap::const_iterator insiter(keyiter); + TextKeyMap groupkeys; + do { + sep = insiter->second.find(':'); + if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) + groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); + else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) + groupkeys.insert(std::make_pair(insiter->first, insiter->second)); + } while(insiter++ != lastkeyiter); + + bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); + } +} + + +Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) +{ + /* We need to be a little aggressive here, since some NIFs have a crap-ton + * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: + * There are no bones used for skinning, there are no controllers on non- + * NiTriShape nodes, there are no nodes named "AttachLight", and the tree + * consists of NiNode, NiTriShape, and RootCollisionNode types only. + */ + if(!node->boneTrafo) + { + if(node->recType == Nif::RC_NiTriShape) + return Ogre::SkeletonPtr(); + if(node->controller.empty() && node->name != "AttachLight") + { + if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) + { + const Nif::NiNode *ninode = static_cast(node); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + { + Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); + if(!skel.isNull()) + return skel; + } + } + return Ogre::SkeletonPtr(); + } + } + } + + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + return skelMgr.create(name, group, true, &sLoaders[name]); +} + +// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be +// used when the bone name is insufficient as this is a relatively slow lookup +int NIFSkeletonLoader::lookupOgreBoneHandle(const std::string &nifname, int idx) +{ + LoaderMap::const_iterator loader = sLoaders.find(nifname); + if(loader != sLoaders.end()) + { + std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); + if(entry != loader->second.mNifToOgreHandleMap.end()) + return entry->second; + } + throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); +} + +NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; + +} diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp new file mode 100644 index 000000000..c69c2a12f --- /dev/null +++ b/components/nifogre/skeleton.hpp @@ -0,0 +1,63 @@ +#ifndef COMPONENTS_NIFOGRE_SKELETON_HPP +#define COMPONENTS_NIFOGRE_SKELETON_HPP + +#include +#include +#include + +#include + +#include "ogrenifloader.hpp" + +namespace Nif +{ + class NiTextKeyExtraData; + class Node; + class NiKeyframeController; +} + +namespace NifOgre +{ + +/** Manual resource loader for NIF skeletons. This is the main class + responsible for translating the internal NIF skeleton structure into + something Ogre can use (includes animations and node TextKeyData). + */ +class NIFSkeletonLoader : public Ogre::ManualResourceLoader +{ + static void warn(const std::string &msg) + { + std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; + } + + static void fail(const std::string &msg) + { + std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; + abort(); + } + + static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); + + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); + void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); + + // Lookup to retrieve an Ogre bone handle for a given Nif record index + std::map mNifToOgreHandleMap; + + typedef std::map LoaderMap; + static LoaderMap sLoaders; + +public: + void loadResource(Ogre::Resource *resource); + + static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); + + // Looks up an Ogre Bone handle ID from a NIF's record index. Should only + // be used when the bone name is insufficient as this is a relatively slow + // lookup + static int lookupOgreBoneHandle(const std::string &nifname, int idx); +}; + +} + +#endif From 39704077722ec64120d6764b8a7e0480cac051be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 20:22:13 -0700 Subject: [PATCH 250/817] Use actual classes for properties --- components/nif/property.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index fd96ad048..06c8260ce 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -156,11 +156,11 @@ public: }; // These contain no other data than the 'flags' field in Property -typedef Property NiShadeProperty; -typedef Property NiDitherProperty; -typedef Property NiZBufferProperty; -typedef Property NiSpecularProperty; -typedef Property NiWireframeProperty; +class NiShadeProperty : public Property { }; +class NiDitherProperty : public Property { }; +class NiZBufferProperty : public Property { }; +class NiSpecularProperty : public Property { }; +class NiWireframeProperty : public Property { }; // The rest are all struct-based template @@ -324,10 +324,10 @@ struct S_StencilProperty } }; -typedef StructPropT NiAlphaProperty; -typedef StructPropT NiMaterialProperty; -typedef StructPropT NiVertexColorProperty; -typedef StructPropT NiStencilProperty; +class NiAlphaProperty : public StructPropT { }; +class NiMaterialProperty : public StructPropT { }; +class NiVertexColorProperty : public StructPropT { }; +class NiStencilProperty : public StructPropT { }; } // Namespace #endif From 75489b1e9d583da765dc3da4aedea0f9e8e7fa9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 20:24:44 -0700 Subject: [PATCH 251/817] Move NIFMaterialLoader to a separate file --- components/CMakeLists.txt | 2 +- components/nifogre/material.cpp | 399 ++++++++++++++++++++++++++ components/nifogre/material.hpp | 57 ++++ components/nifogre/ogrenifloader.cpp | 407 +-------------------------- 4 files changed, 458 insertions(+), 407 deletions(-) create mode 100644 components/nifogre/material.cpp create mode 100644 components/nifogre/material.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d43725ee0..aa422b49e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader skeleton + ogrenifloader skeleton material ) add_component_dir (nifbullet diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp new file mode 100644 index 000000000..431b8219a --- /dev/null +++ b/components/nifogre/material.cpp @@ -0,0 +1,399 @@ +#include "material.hpp" + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + + +namespace NifOgre +{ + +// Conversion of blend / test mode from NIF +static const char *getBlendFactor(int mode) +{ + switch(mode) + { + case 0: return "one"; + case 1: return "zero"; + case 2: return "src_colour"; + case 3: return "one_minus_src_colour"; + case 4: return "dest_colour"; + case 5: return "one_minus_dest_colour"; + case 6: return "src_alpha"; + case 7: return "one_minus_src_alpha"; + case 8: return "dest_alpha"; + case 9: return "one_minus_dest_alpha"; + case 10: return "src_alpha_saturate"; + } + std::cerr<< "Unexpected blend mode: "<colors.size() != 0); + + // Texture + if(texprop) + { + for(int i = 0;i < 7;i++) + { + if(!texprop->textures[i].inUse) + continue; + if(texprop->textures[i].texture.empty()) + { + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); + continue; + } + + const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); + if(st->external) + texName[i] = findTextureName(st->filename); + else + warn("Found internal texture, ignoring."); + } + + Nif::ControllerPtr ctrls = texprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled texture controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); + + // Alpha modifiers + if(alphaprop) + { + alphaFlags = alphaprop->flags; + alphaTest = alphaprop->data.threshold; + + Nif::ControllerPtr ctrls = alphaprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled alpha controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + // Vertex color handling + if(vertprop) + { + vertMode = vertprop->data.vertmode; + // FIXME: Handle lightmode? + //lightMode = vertprop->data.lightmode; + + Nif::ControllerPtr ctrls = vertprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(zprop) + { + depthFlags = zprop->flags; + // Depth function??? + + Nif::ControllerPtr ctrls = zprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled depth controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(specprop) + { + specFlags = specprop->flags; + + Nif::ControllerPtr ctrls = specprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled specular controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(wireprop) + { + wireFlags = wireprop->flags; + + Nif::ControllerPtr ctrls = wireprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + // Material + if(matprop) + { + ambient = matprop->data.ambient; + diffuse = matprop->data.diffuse; + specular = matprop->data.specular; + emissive = matprop->data.emissive; + glossiness = matprop->data.glossiness; + alpha = matprop->data.alpha; + + Nif::ControllerPtr ctrls = matprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled material controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + { + // Generate a hash out of all properties that can affect the material. + size_t h = 0; + boost::hash_combine(h, ambient.x); + boost::hash_combine(h, ambient.y); + boost::hash_combine(h, ambient.z); + boost::hash_combine(h, diffuse.x); + boost::hash_combine(h, diffuse.y); + boost::hash_combine(h, diffuse.z); + boost::hash_combine(h, alpha); + boost::hash_combine(h, specular.x); + boost::hash_combine(h, specular.y); + boost::hash_combine(h, specular.z); + boost::hash_combine(h, glossiness); + boost::hash_combine(h, emissive.x); + boost::hash_combine(h, emissive.y); + boost::hash_combine(h, emissive.z); + for(int i = 0;i < 7;i++) + { + if(!texName[i].empty()) + boost::hash_combine(h, texName[i]); + } + boost::hash_combine(h, vertexColour); + boost::hash_combine(h, alphaFlags); + boost::hash_combine(h, alphaTest); + boost::hash_combine(h, vertMode); + boost::hash_combine(h, depthFlags); + boost::hash_combine(h, specFlags); + boost::hash_combine(h, wireFlags); + + std::map::iterator itr = sMaterialMap.find(h); + if (itr != sMaterialMap.end()) + { + // a suitable material exists already - use it + return itr->second; + } + // not found, create a new one + sMaterialMap.insert(std::make_pair(h, name)); + } + + // No existing material like this. Create a new one. + sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); + if(vertMode == 0 || !vertexColour) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); + } + else if(vertMode == 1) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); + } + else if(vertMode == 2) + { + instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); + } + else + std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( + new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); + } + + if(wireFlags) + { + instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); + } + + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); + instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); + if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) + { + instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) + { + instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) + { + // force automips on normal maps for now + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); + } + + for(int i = 0;i < 7;i++) + { + if(i == Nif::NiTexturingProperty::BaseTexture || + i == Nif::NiTexturingProperty::DetailTexture || + i == Nif::NiTexturingProperty::BumpTexture || + i == Nif::NiTexturingProperty::GlowTexture) + continue; + if(!texName[i].empty()) + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); + } + + if (vertexColour) + instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); + + // Add transparency if NiAlphaProperty was present + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); + if (result.first) + { + alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ + alphaTest = result.second; + depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on + } + + if((alphaFlags&1)) + { + std::string blend_mode; + blend_mode += getBlendFactor((alphaFlags>>1)&0xf); + blend_mode += " "; + blend_mode += getBlendFactor((alphaFlags>>5)&0xf); + instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); + } + + if((alphaFlags>>9)&1) + { + std::string reject; + reject += getTestMode((alphaFlags>>10)&0x7); + reject += " "; + reject += Ogre::StringConverter::toString(alphaTest); + instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); + } + else + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); + + // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( + ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); + + instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); + // depth_func??? + + sh::Factory::getInstance()._ensureMaterial(name, "Default"); + return name; +} + +std::map NIFMaterialLoader::sMaterialMap; + +} diff --git a/components/nifogre/material.hpp b/components/nifogre/material.hpp new file mode 100644 index 000000000..8843ac6c6 --- /dev/null +++ b/components/nifogre/material.hpp @@ -0,0 +1,57 @@ +#ifndef COMPONENTS_NIFOGRE_MATERIAL_HPP +#define COMPONENTS_NIFOGRE_MATERIAL_HPP + +#include +#include +#include +#include + +#include + +namespace Nif +{ + class ShapeData; + class NiTexturingProperty; + class NiMaterialProperty; + class NiAlphaProperty; + class NiVertexColorProperty; + class NiZBufferProperty; + class NiSpecularProperty; + class NiWireframeProperty; +} + +namespace NifOgre +{ + +class NIFMaterialLoader { + static void warn(const std::string &msg) + { + std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; + } + + static void fail(const std::string &msg) + { + std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; + abort(); + } + + static std::map sMaterialMap; + + static std::string findTextureName(const std::string &filename); + +public: + static Ogre::String getMaterial(const Nif::ShapeData *shapedata, + const Ogre::String &name, const Ogre::String &group, + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop, + const Nif::NiWireframeProperty *wireprop, + bool &needTangents); +}; + +} + +#endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 0a30f38bd..3bd93a1b9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -40,18 +40,11 @@ #include #include -#include -#include -#include - -#include - #include #include -#include -#include #include "skeleton.hpp" +#include "material.hpp" namespace std { @@ -424,404 +417,6 @@ public: }; -// Conversion of blend / test mode from NIF -static const char *getBlendFactor(int mode) -{ - switch(mode) - { - case 0: return "one"; - case 1: return "zero"; - case 2: return "src_colour"; - case 3: return "one_minus_src_colour"; - case 4: return "dest_colour"; - case 5: return "one_minus_dest_colour"; - case 6: return "src_alpha"; - case 7: return "one_minus_src_alpha"; - case 8: return "dest_alpha"; - case 9: return "one_minus_dest_alpha"; - case 10: return "src_alpha_saturate"; - } - std::cerr<< "Unexpected blend mode: "< MaterialMap; - -static void warn(const std::string &msg) -{ - std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; -} - -static void fail(const std::string &msg) -{ - std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; - abort(); -} - - -static std::string findTextureName(const std::string &filename) -{ - /* Bethesda at some point converted all their BSA - * textures from tga to dds for increased load speed, but all - * texture file name references were kept as .tga. - */ - static const char path[] = "textures\\"; - static const char path2[] = "textures/"; - - - std::string texname = filename; - Misc::StringUtils::toLower(texname); - - if(texname.compare(0, sizeof(path)-1, path) != 0 - && texname.compare(0, sizeof(path2)-1, path2) != 0) - texname = path + texname; - - Ogre::String::size_type pos = texname.rfind('.'); - if(pos != Ogre::String::npos && texname.compare(pos, texname.length() - pos, ".dds") != 0) - { - // since we know all (GOTY edition or less) textures end - // in .dds, we change the extension - texname.replace(pos, texname.length(), ".dds"); - - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texname)) - { - texname = filename; - Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0 - && texname.compare(0, sizeof(path2)-1, path2) != 0) - texname = path + texname; - } - } - - return texname; -} - -public: -static Ogre::String getMaterial(const Nif::ShapeData *shapedata, - const Ogre::String &name, const Ogre::String &group, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop, - const Nif::NiWireframeProperty *wireprop, - bool &needTangents) -{ - Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); - Ogre::MaterialPtr material = matMgr.getByName(name); - if(!material.isNull()) - return name; - - Ogre::Vector3 ambient(1.0f); - Ogre::Vector3 diffuse(1.0f); - Ogre::Vector3 specular(0.0f); - Ogre::Vector3 emissive(0.0f); - float glossiness = 0.0f; - float alpha = 1.0f; - int alphaFlags = 0; - int alphaTest = 0; - int vertMode = 2; - //int lightMode = 1; - int depthFlags = 3; - // Default should be 1, but Bloodmoon's models are broken - int specFlags = 0; - int wireFlags = 0; - Ogre::String texName[7]; - - bool vertexColour = (shapedata->colors.size() != 0); - - // Texture - if(texprop) - { - for(int i = 0;i < 7;i++) - { - if(!texprop->textures[i].inUse) - continue; - if(texprop->textures[i].texture.empty()) - { - warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); - continue; - } - - const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); - if(st->external) - texName[i] = findTextureName(st->filename); - else - warn("Found internal texture, ignoring."); - } - - Nif::ControllerPtr ctrls = texprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled texture controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); - - // Alpha modifiers - if(alphaprop) - { - alphaFlags = alphaprop->flags; - alphaTest = alphaprop->data.threshold; - - Nif::ControllerPtr ctrls = alphaprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled alpha controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Vertex color handling - if(vertprop) - { - vertMode = vertprop->data.vertmode; - // FIXME: Handle lightmode? - //lightMode = vertprop->data.lightmode; - - Nif::ControllerPtr ctrls = vertprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(zprop) - { - depthFlags = zprop->flags; - // Depth function??? - - Nif::ControllerPtr ctrls = zprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled depth controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(specprop) - { - specFlags = specprop->flags; - - Nif::ControllerPtr ctrls = specprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled specular controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(wireprop) - { - wireFlags = wireprop->flags; - - Nif::ControllerPtr ctrls = wireprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Material - if(matprop) - { - ambient = matprop->data.ambient; - diffuse = matprop->data.diffuse; - specular = matprop->data.specular; - emissive = matprop->data.emissive; - glossiness = matprop->data.glossiness; - alpha = matprop->data.alpha; - - Nif::ControllerPtr ctrls = matprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled material controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - { - // Generate a hash out of all properties that can affect the material. - size_t h = 0; - boost::hash_combine(h, ambient.x); - boost::hash_combine(h, ambient.y); - boost::hash_combine(h, ambient.z); - boost::hash_combine(h, diffuse.x); - boost::hash_combine(h, diffuse.y); - boost::hash_combine(h, diffuse.z); - boost::hash_combine(h, alpha); - boost::hash_combine(h, specular.x); - boost::hash_combine(h, specular.y); - boost::hash_combine(h, specular.z); - boost::hash_combine(h, glossiness); - boost::hash_combine(h, emissive.x); - boost::hash_combine(h, emissive.y); - boost::hash_combine(h, emissive.z); - for(int i = 0;i < 7;i++) - { - if(!texName[i].empty()) - boost::hash_combine(h, texName[i]); - } - boost::hash_combine(h, vertexColour); - boost::hash_combine(h, alphaFlags); - boost::hash_combine(h, alphaTest); - boost::hash_combine(h, vertMode); - boost::hash_combine(h, depthFlags); - boost::hash_combine(h, specFlags); - boost::hash_combine(h, wireFlags); - - std::map::iterator itr = MaterialMap.find(h); - if (itr != MaterialMap.end()) - { - // a suitable material exists already - use it - return itr->second; - } - // not found, create a new one - MaterialMap.insert(std::make_pair(h, name)); - } - - // No existing material like this. Create a new one. - sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); - if(vertMode == 0 || !vertexColour) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); - } - else if(vertMode == 1) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); - } - else if(vertMode == 2) - { - instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); - } - else - std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); - } - - if(wireFlags) - { - instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); - } - - instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); - instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); - instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); - if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) - { - instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); - } - if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) - { - instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); - } - if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) - { - // force automips on normal maps for now - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); - } - - for(int i = 0;i < 7;i++) - { - if(i == Nif::NiTexturingProperty::BaseTexture || - i == Nif::NiTexturingProperty::DetailTexture || - i == Nif::NiTexturingProperty::BumpTexture || - i == Nif::NiTexturingProperty::GlowTexture) - continue; - if(!texName[i].empty()) - warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); - } - - if (vertexColour) - instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); - - // Add transparency if NiAlphaProperty was present - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); - if (result.first) - { - alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ - alphaTest = result.second; - depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on - } - - if((alphaFlags&1)) - { - std::string blend_mode; - blend_mode += getBlendFactor((alphaFlags>>1)&0xf); - blend_mode += " "; - blend_mode += getBlendFactor((alphaFlags>>5)&0xf); - instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); - } - - if((alphaFlags>>9)&1) - { - std::string reject; - reject += getTestMode((alphaFlags>>10)&0x7); - reject += " "; - reject += Ogre::StringConverter::toString(alphaTest); - instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); - } - else - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - - // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( - ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); - - instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); - // depth_func??? - - sh::Factory::getInstance()._ensureMaterial(name, "Default"); - return name; -} - -}; -std::map NIFMaterialLoader::MaterialMap; - - /** Manual resource loader for NIF objects (meshes, particle systems, etc). * This is the main class responsible for translating the internal NIF * structures into something Ogre can use. From 6128b9276f35d75c6fccb5a05e458fc8537ac5bc Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Thu, 11 Apr 2013 00:21:56 -0400 Subject: [PATCH 252/817] Removed non-essential includes from all MWGui header files. --- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.hpp | 4 ---- apps/openmw/mwgui/container.hpp | 3 --- apps/openmw/mwgui/cursor.hpp | 1 - apps/openmw/mwgui/dialogue.hpp | 3 --- apps/openmw/mwgui/dialoguehistory.hpp | 1 + apps/openmw/mwgui/enchantingdialog.hpp | 2 -- apps/openmw/mwgui/hud.hpp | 2 -- apps/openmw/mwgui/itemselection.hpp | 2 -- apps/openmw/mwgui/journalwindow.hpp | 3 --- apps/openmw/mwgui/list.hpp | 1 - apps/openmw/mwgui/loadingscreen.hpp | 1 - apps/openmw/mwgui/messagebox.hpp | 2 -- apps/openmw/mwgui/quickkeysmenu.hpp | 1 - apps/openmw/mwgui/race.hpp | 5 ----- apps/openmw/mwgui/repair.hpp | 1 - apps/openmw/mwgui/review.hpp | 1 - apps/openmw/mwgui/statswindow.hpp | 5 ----- apps/openmw/mwgui/tradewindow.hpp | 3 --- apps/openmw/mwgui/travelwindow.hpp | 3 --- apps/openmw/mwgui/widgets.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ----- 22 files changed, 2 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index c61d2f92b..655a832c1 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,12 +5,12 @@ #include "../mwmechanics/alchemy.hpp" -#include "windowbase.hpp" #include "container.hpp" #include "widgets.hpp" namespace MWGui { + class AlchemyWindow : public WindowBase, public ContainerBase { public: diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index fed77e889..586faf966 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -1,13 +1,9 @@ #ifndef CHARACTER_CREATION_HPP #define CHARACTER_CREATION_HPP -#include "../mwworld/esmstore.hpp" - #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/stat.hpp" - namespace MWGui { class WindowBase; diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 521ac8cc3..8440c6444 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -1,13 +1,10 @@ #ifndef MGUI_CONTAINER_H #define MGUI_CONTAINER_H -#include "../mwworld/esmstore.hpp" - #include "windowbase.hpp" #include "referenceinterface.hpp" #include "../mwclass/container.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwgui/cursor.hpp b/apps/openmw/mwgui/cursor.hpp index 3a4a05f4c..badf82262 100644 --- a/apps/openmw/mwgui/cursor.hpp +++ b/apps/openmw/mwgui/cursor.hpp @@ -3,7 +3,6 @@ #include #include -#include namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a1bbee02c..74fa8051c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -3,9 +3,6 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" -#include - -#include "../mwworld/ptr.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/dialoguehistory.hpp b/apps/openmw/mwgui/dialoguehistory.hpp index c37504af7..4cf6de621 100644 --- a/apps/openmw/mwgui/dialoguehistory.hpp +++ b/apps/openmw/mwgui/dialoguehistory.hpp @@ -1,5 +1,6 @@ #ifndef MWGUI_DIALOGE_HISTORY_H #define MWGUI_DIALOGE_HISTORY_H + #include namespace MWGui diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index c727a0974..8bad60c8e 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_ENCHANTINGDIALOG_H #define MWGUI_ENCHANTINGDIALOG_H -#include "windowbase.hpp" -#include "referenceinterface.hpp" #include "spellcreationdialog.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index c65566ce3..1dd53683b 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -1,7 +1,5 @@ #include "mapwindow.hpp" -#include - #include "../mwmechanics/stat.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 3e812d26c..19007de6b 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -1,7 +1,5 @@ #include "container.hpp" -#include "../mwworld/ptr.hpp" - namespace MWGui { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 7670b65f5..da05a6f0e 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,10 +1,7 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H -#include -#include #include -#include #include "windowbase.hpp" #include "imagebutton.hpp" diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index 09e42e865..956523c0d 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -1,7 +1,6 @@ #ifndef MWGUI_LIST_HPP #define MWGUI_LIST_HPP -#include #include namespace MWGui diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 12e6504bc..87cedaa98 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -2,7 +2,6 @@ #define MWGUI_LOADINGSCREEN_H #include -#include #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index cb4073902..0df6f3544 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_MESSAGE_BOX_H #define MWGUI_MESSAGE_BOX_H -#include - #include "windowbase.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 646ec2aa4..058519ece 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -1,7 +1,6 @@ #ifndef MWGUI_QUICKKEYS_H #define MWGUI_QUICKKEYS_H - #include "../mwworld/ptr.hpp" #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index f3adce444..893c4c90b 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -1,11 +1,6 @@ #ifndef MWGUI_RACE_H #define MWGUI_RACE_H - -#include - -#include "../mwworld/esmstore.hpp" - #include "../mwrender/characterpreview.hpp" #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 5d9a48719..d0f5c54c4 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -3,7 +3,6 @@ #include "windowbase.hpp" -#include "../mwworld/ptr.hpp" #include "../mwmechanics/repair.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index d5df94e28..87d6fedfa 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -2,7 +2,6 @@ #define MWGUI_REVIEW_H #include "windowbase.hpp" -#include "../mwmechanics/stat.hpp" #include "widgets.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 4b723048c..bec42d029 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -3,11 +3,6 @@ #include "../mwworld/esmstore.hpp" -#include -#include -#include -#include - #include "../mwmechanics/stat.hpp" #include "windowpinnablebase.hpp" diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index e526a42ca..892ce0297 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -2,9 +2,6 @@ #define MWGUI_TRADEWINDOW_H #include "container.hpp" -#include "windowbase.hpp" - -#include "../mwworld/ptr.hpp" namespace MyGUI { diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index a814d0478..f2a23b048 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -2,9 +2,6 @@ #define MWGUI_TravelWINDOW_H #include "container.hpp" -#include "windowbase.hpp" - -#include "../mwworld/ptr.hpp" namespace MyGUI { diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 038ce3f86..156794691 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -4,8 +4,6 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/stat.hpp" -#include -#include #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3c9fc586a..652ad870f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -10,11 +10,6 @@ this class. **/ -#include -#include - -#include - #include "../mwbase/windowmanager.hpp" namespace MyGUI From 62e0abd94582060951c887ac6a1782ea1644aa2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 22:38:46 -0700 Subject: [PATCH 253/817] Move the mesh loader to its own source file --- components/CMakeLists.txt | 2 +- components/nifogre/mesh.cpp | 375 +++++++++++++++++++ components/nifogre/mesh.hpp | 55 +++ components/nifogre/ogrenifloader.cpp | 526 +++++---------------------- 4 files changed, 516 insertions(+), 442 deletions(-) create mode 100644 components/nifogre/mesh.cpp create mode 100644 components/nifogre/mesh.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index aa422b49e..dd8f78eda 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader skeleton material + ogrenifloader skeleton material mesh ) add_component_dir (nifbullet diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp new file mode 100644 index 000000000..3780306f6 --- /dev/null +++ b/components/nifogre/mesh.cpp @@ -0,0 +1,375 @@ +#include "mesh.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "material.hpp" + +namespace NifOgre +{ + +void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop); + +// Helper class that computes the bounding box and of a mesh +class BoundsFinder +{ + struct MaxMinFinder + { + float max, min; + + MaxMinFinder() + { + min = std::numeric_limits::infinity(); + max = -min; + } + + void add(float f) + { + if (f > max) max = f; + if (f < min) min = f; + } + + // Return Max(max**2, min**2) + float getMaxSquared() + { + float m1 = max*max; + float m2 = min*min; + if (m1 >= m2) return m1; + return m2; + } + }; + + MaxMinFinder X, Y, Z; + +public: + // Add 'verts' vertices to the calculation. The 'data' pointer is + // expected to point to 3*verts floats representing x,y,z for each + // point. + void add(float *data, int verts) + { + for (int i=0;idata.getPtr(); + const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); + std::vector srcVerts = data->vertices; + std::vector srcNorms = data->normals; + Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; + bool vertShadowBuffer = false; + if(skin != NULL) + { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + + // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be + // explicitly attached later. + mesh->setSkeletonName(mName); + + // Get the skeleton resource, so vertices can be transformed into the bones' initial state. + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + skel = skelMgr->getByName(mName); + + // Convert vertices and normals to bone space from bind position. It would be + // better to transform the bones into bind position, but there doesn't seem to + // be a reliable way to do that. + std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); + std::vector newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) + { + Ogre::Bone *bone = skel->getBone(bones[b]->name); + Ogre::Matrix4 mat; + mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), + Ogre::Quaternion(data->bones[b].trafo.rotation)); + mat = bone->_getFullTransform() * mat; + + const std::vector &weights = data->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) + { + size_t index = weights[i].vertex; + float weight = weights[i].weight; + + newVerts.at(index) += (mat*srcVerts[index]) * weight; + if(newNorms.size() > index) + { + Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); + vec4 = mat*vec4 * weight; + newNorms[index] += Ogre::Vector3(&vec4[0]); + } + } + } + + srcVerts = newVerts; + srcNorms = newNorms; + } + else + { + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(skelMgr->getByName(mName).isNull()) + { + // No skinning and no skeleton, so just transform the vertices and + // normals into position. + Ogre::Matrix4 mat4 = shape->getWorldTransform(); + for(size_t i = 0;i < srcVerts.size();i++) + { + Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); + vec4 = mat4*vec4; + srcVerts[i] = Ogre::Vector3(&vec4[0]); + } + for(size_t i = 0;i < srcNorms.size();i++) + { + Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); + vec4 = mat4*vec4; + srcNorms[i] = Ogre::Vector3(&vec4[0]); + } + } + } + + // Set the bounding box first + BoundsFinder bounds; + bounds.add(&srcVerts[0][0], srcVerts.size()); + if(!bounds.isValid()) + { + float v[3] = { 0.0f, 0.0f, 0.0f }; + bounds.add(&v[0], 1); + } + + mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, + bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); + mesh->_setBoundingSphereRadius(bounds.getRadius()); + + // This function is just one long stream of Ogre-barf, but it works + // great. + Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); + Ogre::HardwareVertexBufferSharedPtr vbuf; + Ogre::HardwareIndexBufferSharedPtr ibuf; + Ogre::VertexBufferBinding *bind; + Ogre::VertexDeclaration *decl; + int nextBuf = 0; + + Ogre::SubMesh *sub = mesh->createSubMesh(); + + // Add vertices + sub->useSharedVertices = false; + sub->vertexData = new Ogre::VertexData(); + sub->vertexData->vertexStart = 0; + sub->vertexData->vertexCount = srcVerts.size(); + + decl = sub->vertexData->vertexDeclaration; + bind = sub->vertexData->vertexBufferBinding; + if(srcVerts.size()) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), + srcVerts.size(), vertUsage, vertShadowBuffer); + vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); + bind->setBinding(nextBuf++, vbuf); + } + + // Vertex normals + if(srcNorms.size()) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), + srcNorms.size(), vertUsage, vertShadowBuffer); + vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); + bind->setBinding(nextBuf++, vbuf); + } + + // Vertex colors + const std::vector &colors = data->colors; + if(colors.size()) + { + Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem(); + std::vector colorsRGB(colors.size()); + for(size_t i = 0;i < colorsRGB.size();i++) + { + Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); + rs->convertColourValue(clr, &colorsRGB[i]); + } + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), + colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); + vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); + decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); + bind->setBinding(nextBuf++, vbuf); + } + + // Texture UV coordinates + size_t numUVs = data->uvlist.size(); + for(size_t i = 0;i < numUVs;i++) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), + srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); + vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + bind->setBinding(nextBuf++, vbuf); + } + + // Triangle faces + const std::vector &srcIdx = data->triangles; + if(srcIdx.size()) + { + ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), + Ogre::HardwareBuffer::HBU_STATIC); + ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); + sub->indexData->indexBuffer = ibuf; + sub->indexData->indexCount = srcIdx.size(); + sub->indexData->indexStart = 0; + } + + // Assign bone weights for this TriShape + if(skin != NULL) + { + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t i = 0;i < bones.length();i++) + { + Ogre::VertexBoneAssignment boneInf; + boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); + + const std::vector &weights = data->bones[i].weights; + for(size_t j = 0;j < weights.size();j++) + { + boneInf.vertexIndex = weights[j].vertex; + boneInf.weight = weights[j].weight; + sub->addBoneAssignment(boneInf); + } + } + } + + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; + bool needTangents = false; + + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + wireprop, needTangents); + if(matname.length() > 0) + sub->setMaterialName(matname); + + // build tangents if the material needs them + if (needTangents) + { + unsigned short src,dest; + if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) + mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); + } +} + + +NIFMeshLoader::NIFMeshLoader(const std::string &name, const std::string &group, size_t idx) + : mName(name), mGroup(group), mShapeIndex(idx) +{ +} + +void NIFMeshLoader::loadResource(Ogre::Resource *resource) +{ + Ogre::Mesh *mesh = dynamic_cast(resource); + OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); + + Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); + if(mShapeIndex >= nif->numRecords()) + { + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(!skelMgr->getByName(mName).isNull()) + mesh->setSkeletonName(mName); + return; + } + + const Nif::Record *record = nif->getRecord(mShapeIndex); + createSubMesh(mesh, dynamic_cast(record)); +} + + +void NIFMeshLoader::createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx) +{ + NIFMeshLoader::LoaderMap::iterator loader; + loader = sLoaders.insert(std::make_pair(fullname, NIFMeshLoader(name, group, idx))).first; + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + Ogre::MeshPtr mesh = meshMgr.createManual(fullname, group, &loader->second); + mesh->setAutoBuildEdgeLists(false); +} + +} diff --git a/components/nifogre/mesh.hpp b/components/nifogre/mesh.hpp new file mode 100644 index 000000000..731e49c90 --- /dev/null +++ b/components/nifogre/mesh.hpp @@ -0,0 +1,55 @@ +#ifndef COMPONENTS_NIFOGRE_MESH_HPP +#define COMPONENTS_NIFOGRE_MESH_HPP + +#include +#include +#include +#include + +#include + +namespace Nif +{ + class NiTriShape; +} + +namespace NifOgre +{ + +/** Manual resource loader for NiTriShapes. This is the main class responsible + * for translating the internal NIF meshes into something Ogre can use. + */ +class NIFMeshLoader : Ogre::ManualResourceLoader +{ + static void warn(const std::string &msg) + { + std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + } + + static void fail(const std::string &msg) + { + std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + abort(); + } + + std::string mName; + std::string mGroup; + size_t mShapeIndex; + + // Convert NiTriShape to Ogre::SubMesh + void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape); + + typedef std::map LoaderMap; + static LoaderMap sLoaders; + + NIFMeshLoader(const std::string &name, const std::string &group, size_t idx); + + virtual void loadResource(Ogre::Resource *resource); + +public: + static void createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx); +}; + +} + +#endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3bd93a1b9..8d82c3ced 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -25,12 +25,7 @@ #include -#include -#include -#include -#include #include -#include #include #include #include @@ -38,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -45,6 +42,7 @@ #include "skeleton.hpp" #include "material.hpp" +#include "mesh.hpp" namespace std { @@ -58,6 +56,46 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { +void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop) +{ + if(node->parent) + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + + const Nif::PropertyList &proplist = node->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); + else + std::cerr<< "Unhandled property type: "<recName < { @@ -332,101 +370,13 @@ public: }; -// Helper class that computes the bounding box and of a mesh -class BoundsFinder -{ - struct MaxMinFinder - { - float max, min; - - MaxMinFinder() - { - min = std::numeric_limits::infinity(); - max = -min; - } - - void add(float f) - { - if (f > max) max = f; - if (f < min) min = f; - } - - // Return Max(max**2, min**2) - float getMaxSquared() - { - float m1 = max*max; - float m2 = min*min; - if (m1 >= m2) return m1; - return m2; - } - }; - - MaxMinFinder X, Y, Z; - -public: - // Add 'verts' vertices to the calculation. The 'data' pointer is - // expected to point to 3*verts floats representing x,y,z for each - // point. - void add(float *data, int verts) - { - for (int i=0;iparent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - } - - // Convert NiTriShape to Ogre::SubMesh - void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) - { - Ogre::SkeletonPtr skel; - const Nif::NiTriShapeData *data = shape->data.getPtr(); - const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); - std::vector srcVerts = data->vertices; - std::vector srcNorms = data->normals; - Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; - bool vertShadowBuffer = false; - if(skin != NULL) - { - vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; - vertShadowBuffer = true; - - // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be - // explicitly attached later. - mesh->setSkeletonName(mName); - - // Get the skeleton resource, so vertices can be transformed into the bones' initial state. - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - skel = skelMgr->getByName(mName); - - // Convert vertices and normals to bone space from bind position. It would be - // better to transform the bones into bind position, but there doesn't seem to - // be a reliable way to do that. - std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); - std::vector newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) - { - Ogre::Bone *bone = skel->getBone(bones[b]->name); - Ogre::Matrix4 mat; - mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), - Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bone->_getFullTransform() * mat; - - const std::vector &weights = data->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) - { - size_t index = weights[i].vertex; - float weight = weights[i].weight; - - newVerts.at(index) += (mat*srcVerts[index]) * weight; - if(newNorms.size() > index) - { - Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); - vec4 = mat*vec4 * weight; - newNorms[index] += Ogre::Vector3(&vec4[0]); - } - } - } - - srcVerts = newVerts; - srcNorms = newNorms; - } - else - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(skelMgr->getByName(mName).isNull()) - { - // No skinning and no skeleton, so just transform the vertices and - // normals into position. - Ogre::Matrix4 mat4 = shape->getWorldTransform(); - for(size_t i = 0;i < srcVerts.size();i++) - { - Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); - vec4 = mat4*vec4; - srcVerts[i] = Ogre::Vector3(&vec4[0]); - } - for(size_t i = 0;i < srcNorms.size();i++) - { - Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); - vec4 = mat4*vec4; - srcNorms[i] = Ogre::Vector3(&vec4[0]); - } - } - } - - // Set the bounding box first - BoundsFinder bounds; - bounds.add(&srcVerts[0][0], srcVerts.size()); - if(!bounds.isValid()) - { - float v[3] = { 0.0f, 0.0f, 0.0f }; - bounds.add(&v[0], 1); - } - - mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, - bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); - mesh->_setBoundingSphereRadius(bounds.getRadius()); - - // This function is just one long stream of Ogre-barf, but it works - // great. - Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareVertexBufferSharedPtr vbuf; - Ogre::HardwareIndexBufferSharedPtr ibuf; - Ogre::VertexBufferBinding *bind; - Ogre::VertexDeclaration *decl; - int nextBuf = 0; - - Ogre::SubMesh *sub = mesh->createSubMesh(); - - // Add vertices - sub->useSharedVertices = false; - sub->vertexData = new Ogre::VertexData(); - sub->vertexData->vertexStart = 0; - sub->vertexData->vertexCount = srcVerts.size(); - - decl = sub->vertexData->vertexDeclaration; - bind = sub->vertexData->vertexBufferBinding; - if(srcVerts.size()) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcVerts.size(), vertUsage, vertShadowBuffer); - vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); - bind->setBinding(nextBuf++, vbuf); - } - - // Vertex normals - if(srcNorms.size()) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcNorms.size(), vertUsage, vertShadowBuffer); - vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); - bind->setBinding(nextBuf++, vbuf); - } - - // Vertex colors - const std::vector &colors = data->colors; - if(colors.size()) - { - Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); - std::vector colorsRGB(colors.size()); - for(size_t i = 0;i < colorsRGB.size();i++) - { - Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); - rs->convertColourValue(clr, &colorsRGB[i]); - } - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); - bind->setBinding(nextBuf++, vbuf); - } - - // Texture UV coordinates - size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); - bind->setBinding(nextBuf++, vbuf); - } - - // Triangle faces - const std::vector &srcIdx = data->triangles; - if(srcIdx.size()) - { - ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), - Ogre::HardwareBuffer::HBU_STATIC); - ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); - sub->indexData->indexBuffer = ibuf; - sub->indexData->indexCount = srcIdx.size(); - sub->indexData->indexStart = 0; - } - - // Assign bone weights for this TriShape - if(skin != NULL) - { - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t i = 0;i < bones.length();i++) - { - Ogre::VertexBoneAssignment boneInf; - boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); - - const std::vector &weights = data->bones[i].weights; - for(size_t j = 0;j < weights.size();j++) - { - boneInf.vertexIndex = weights[j].vertex; - boneInf.weight = weights[j].weight; - sub->addBoneAssignment(boneInf); - } - } - } - - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - bool needTangents = false; - - getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, needTangents); - if(matname.length() > 0) - sub->setMaterialName(matname); - - // build tangents if the material needs them - if (needTangents) - { - unsigned short src,dest; - if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) - mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); - } - } - - - typedef std::map LoaderMap; - static LoaderMap sLoaders; - static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { @@ -743,8 +428,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } } - Ogre::ParticleSystem *createParticleSystem(Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, - const Nif::Node *partnode) + static Ogre::ParticleSystem *createParticleSystem(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, + const Nif::Node *partnode) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -754,7 +440,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); try { - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); if(partnode->name.length() > 0) fullname += "@type="+partnode->name; Misc::StringUtils::toLower(fullname); @@ -769,7 +455,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader bool needTangents = false; getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, needTangents)); @@ -789,7 +475,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader createParticleEmitterAffectors(partsys, partctrl); if(!partctrl->emitter.empty() && !partsys->isAttached()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partctrl->emitter->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); entitybase->attachObjectToBone(trgtbone->getName(), partsys); } @@ -799,7 +485,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(!partsys->isAttached()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partnode->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); entitybase->attachObjectToBone(trgtbone->getName(), partsys); } @@ -813,29 +499,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } - NIFObjectLoader(const std::string &name, const std::string &group) - : mName(name), mGroup(group), mShapeIndex(~(size_t)0) - { } - - virtual void loadResource(Ogre::Resource *resource) - { - Ogre::Mesh *mesh = dynamic_cast(resource); - OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); - - Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); - if(mShapeIndex >= nif->numRecords()) - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(!skelMgr->getByName(mName).isNull()) - mesh->setSkeletonName(mName); - return; - } - - const Nif::Record *record = nif->getRecord(mShapeIndex); - createSubMesh(mesh, dynamic_cast(record)); - } - - void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags=0) + static void createObjects(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, const Nif::Node *node, + ObjectList &objectlist, int flags=0) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -868,7 +534,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiCamera) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, node->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mCameras.push_back(trgtbone); } @@ -880,7 +546,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader { const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::ControllerValueRealPtr srcval; /* Filled in later */ Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); @@ -893,7 +559,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); if(!key->data.empty()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::ControllerValueRealPtr srcval; /* Filled in later */ Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); @@ -909,24 +575,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader { const Nif::NiTriShape *shape = static_cast(node); - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); if(shape->name.length() > 0) fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - Ogre::MeshPtr mesh = meshMgr.getByName(fullname); - if(mesh.isNull()) - { - NIFObjectLoader *loader = &sLoaders[fullname]; - *loader = *this; - loader->mShapeIndex = shape->recIndex; - mesh = meshMgr.createManual(fullname, mGroup, loader); - mesh->setAutoBuildEdgeLists(false); - } + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + if(meshMgr.getByName(fullname).isNull()) + NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - Ogre::Entity *entity = sceneMgr->createEntity(mesh); + Ogre::Entity *entity = sceneMgr->createEntity(fullname); entity->setVisible(!(flags&0x01)); objectlist.mEntities.push_back(entity); @@ -936,7 +594,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader entity->shareSkeletonInstanceWith(objectlist.mSkelBase); else { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } @@ -963,7 +621,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) { - Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, objectlist.mSkelBase, node); + Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) { partsys->setVisible(!(flags&0x01)); @@ -978,71 +636,57 @@ class NIFObjectLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(sceneMgr, children[i].getPtr(), objectlist, flags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags); } } } - void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist) + static void createSkelBase(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, const Nif::Node *node, + ObjectList &objectlist) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all * other meshes are hidden or entities attached to a specific node * instead of skinned. */ - std::string fullname = mName; - Misc::StringUtils::toLower(fullname); - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - Ogre::MeshPtr mesh = meshMgr.getByName(fullname); - if(mesh.isNull()) - { - NIFObjectLoader *loader = &sLoaders[fullname]; - *loader = *this; + if(meshMgr.getByName(name).isNull()) + NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); - mesh = meshMgr.createManual(fullname, mGroup, loader); - mesh->setAutoBuildEdgeLists(false); - } - objectlist.mSkelBase = sceneMgr->createEntity(mesh); + objectlist.mSkelBase = sceneMgr->createEntity(name); objectlist.mEntities.push_back(objectlist.mSkelBase); } public: - NIFObjectLoader() : mShapeIndex(~(size_t)0) - { } - static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) { - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRoots() < 1) + Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); + if(nif->numRoots() < 1) { - nif.warn("Found no root nodes in "+name+"."); + nif->warn("Found no root nodes in "+name+"."); return; } - // The first record is assumed to be the root node - const Nif::Record *r = nif.getRoot(0); + const Nif::Record *r = nif->getRoot(0); assert(r != NULL); - const Nif::Node *node = dynamic_cast(r); + const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First root in "+name+" was not a node, but a "+ - r->recName+"."); + nif->warn("First root in "+name+" was not a node, but a "+ + r->recName+"."); return; } - bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); - if(!hasSkel) - hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - - NIFObjectLoader meshldr(name, group); - if(hasSkel) - meshldr.createSkelBase(sceneMgr, node, objectlist); - meshldr.createObjects(sceneMgr, node, objectlist); + if(Ogre::SkeletonManager::getSingleton().resourceExists(name) || + !NIFSkeletonLoader::createSkeleton(name, group, node).isNull()) + { + // Create a base skeleton entity if this NIF needs one + createSkelBase(name, group, sceneMgr, node, objectlist); + } + createObjects(name, group, sceneMgr, node, objectlist); } }; -NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; ObjectList Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) From d26ffe9de02dfd69a7477eae31349c6a9efbca94 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 23:19:47 -0700 Subject: [PATCH 254/817] Move a method to the Node class --- components/nif/niffile.cpp | 38 +++++++++++++++++++++++++ components/nif/node.hpp | 8 ++++++ components/nifogre/mesh.cpp | 11 +------- components/nifogre/ogrenifloader.cpp | 42 +--------------------------- 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 44eae2953..3b41e96a7 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -384,6 +384,44 @@ void NiSkinInstance::post(NIFFile *nif) } } + +void Node::getProperties(const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop) const +{ + if(parent) + parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + + for(size_t i = 0;i < props.length();i++) + { + // Entries may be empty + if(props[i].empty()) + continue; + + const Nif::Property *pr = props[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); + else + std::cerr<< "Unhandled property type: "<recName <getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8d82c3ced..48893bf4a 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -56,46 +56,6 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { -void getNodeProperties(const Nif::Node *node, - const Nif::NiTexturingProperty *&texprop, - const Nif::NiMaterialProperty *&matprop, - const Nif::NiAlphaProperty *&alphaprop, - const Nif::NiVertexColorProperty *&vertprop, - const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop) -{ - if(node->parent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else - std::cerr<< "Unhandled property type: "<recName < { @@ -454,7 +414,7 @@ class NIFObjectLoader const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, texprop, matprop, alphaprop, vertprop, zprop, specprop, From 6d3a2cd5a0c5364395cdad5aeedb291abeffc1e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 10:50:22 +0200 Subject: [PATCH 255/817] added comment token (for use in syntax colouring) --- components/compiler/parser.cpp | 5 +++++ components/compiler/parser.hpp | 7 +++++++ components/compiler/scanner.cpp | 9 ++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 896458e48..8d11c4086 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -148,6 +148,11 @@ namespace Compiler return false; } + bool Parser::parseComment (const std::string& comment, const TokenLoc& loc, Scanner& scanner) + { + return true; + } + // Handle an EOF token. // // - Default-implementation: Report an error. diff --git a/components/compiler/parser.hpp b/components/compiler/parser.hpp index 221e7c2c9..4fec570e9 100644 --- a/components/compiler/parser.hpp +++ b/components/compiler/parser.hpp @@ -82,6 +82,13 @@ namespace Compiler /// /// - Default-implementation: Report an error. + virtual bool parseComment (const std::string& comment, const TokenLoc& loc, + Scanner& scanner); + ///< Handle comment token. + /// \return fetch another token? + /// + /// - Default-implementation: ignored (and return true). + virtual void parseEOF (Scanner& scanner); ///< Handle EOF token. /// diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 420fd8f7f..38a9265a1 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -88,6 +88,10 @@ namespace Compiler } else if (c==';') { + std::string comment; + + comment += c; + while (get (c)) { if (c=='\n') @@ -95,11 +99,14 @@ namespace Compiler putback (c); break; } + else + comment += c; } + TokenLoc loc (mLoc); mLoc.mLiteral.clear(); - return true; + return parser.parseComment (comment, loc, *this); } else if (isWhitespace (c)) { From f17cebde0aea9e8cc1aaedd3592923eb5618c0fb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 10:50:35 +0200 Subject: [PATCH 256/817] syntax colouring for comments --- apps/opencs/view/world/scripthighlighter.cpp | 15 ++++++++++++++- apps/opencs/view/world/scripthighlighter.hpp | 7 +++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 1e93ac26b..288a3d12a 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -40,6 +40,13 @@ bool CSVWorld::ScriptHighlighter::parseSpecial (int code, const Compiler::TokenL return true; } +bool CSVWorld::ScriptHighlighter::parseComment (const std::string& comment, + const Compiler::TokenLoc& loc, Compiler::Scanner& scanner) +{ + highlight (loc, Type_Comment); + return true; +} + void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner) {} @@ -67,7 +74,7 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) { QTextCharFormat format; - format.setForeground (Qt::green); + format.setForeground (Qt::magenta); mScheme.insert (std::make_pair (Type_Float, format)); } @@ -88,6 +95,12 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) format.setForeground (Qt::darkYellow); mScheme.insert (std::make_pair (Type_Special, format)); } + + { + QTextCharFormat format; + format.setForeground (Qt::green); + mScheme.insert (std::make_pair (Type_Comment, format)); + } } void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp index e9918f99b..3ef697809 100644 --- a/apps/opencs/view/world/scripthighlighter.hpp +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -22,7 +22,8 @@ namespace CSVWorld Type_Float, Type_Name, Type_Keyword, - Type_Special + Type_Special, + Type_Comment }; private: @@ -58,7 +59,9 @@ namespace CSVWorld ///< Handle a special character token. /// \return fetch another token? - ///< Handle a special character token. + virtual bool parseComment (const std::string& comment, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle comment token. /// \return fetch another token? virtual void parseEOF (Compiler::Scanner& scanner); From 9c7ad758169c0a539b629540e3123348060505b2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 14:44:02 +0200 Subject: [PATCH 257/817] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index f06377500..6456e30a1 100644 --- a/credits.txt +++ b/credits.txt @@ -16,6 +16,7 @@ Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) athile +Britt Mathis (galdor557) BrotherBrick Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) From 2c70074dd745b083cdc99f38fff89e5e5f0776b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Apr 2013 20:25:03 +0200 Subject: [PATCH 258/817] Fix combinedAlpha --- files/materials/terrain.shader | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index de90a6cf6..58146118e 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -227,7 +227,8 @@ #if !IS_FIRST_PASS -float combinedAlpha = 0.f; +// Opacity the previous passes should have, i.e. 1 - (opacity of this pass) +float previousAlpha = 1.f; #endif // Layer calculations @@ -252,7 +253,7 @@ float combinedAlpha = 0.f; #else albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); #endif - combinedAlpha += blendValues@shPropertyString(blendmap_component_@shIterator); + previousAlpha *= 1.f-blendValues@shPropertyString(blendmap_component_@shIterator); #endif @shEndForeach @@ -344,7 +345,7 @@ float combinedAlpha = 0.f; #if IS_FIRST_PASS shOutputColour(0).a = 1; #else - shOutputColour(0).a = min(combinedAlpha, 1.f); + shOutputColour(0).a = 1.f-previousAlpha; #endif } From b98063bba03473d9dc0a7e0c3953069eb1a26ee9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Apr 2013 18:02:44 +0200 Subject: [PATCH 259/817] Fix deleted pointer access (getPosition, getRotation) --- libs/openengine/bullet/physic.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index f71fa4320..524f57c1c 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -19,7 +19,7 @@ namespace Physic PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) - , mBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) + , mBody(0), mRaycastingBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) { // FIXME: Force player to start in no-collision mode for now, until he spawns at a proper door marker. if(name == "player") @@ -47,6 +47,7 @@ namespace Physic void PhysicActor::enableCollisions(bool collision) { + assert(mBody); if(collision && !collisionMode) mBody->translate(btVector3(0,0,-1000)); if(!collision && collisionMode) mBody->translate(btVector3(0,0,1000)); collisionMode = collision; @@ -55,6 +56,7 @@ namespace Physic void PhysicActor::setPosition(const Ogre::Vector3 &pos) { + assert(mBody); if(pos != getPosition()) { mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); @@ -64,6 +66,7 @@ namespace Physic void PhysicActor::setRotation(const Ogre::Quaternion &quat) { + assert(mBody); if(!quat.equals(getRotation(), Ogre::Radian(0))){ mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); mEngine->adjustRigidBody(mRaycastingBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); @@ -74,6 +77,7 @@ namespace Physic Ogre::Vector3 PhysicActor::getPosition() { + assert(mBody); btVector3 vec = mBody->getWorldTransform().getOrigin(); Ogre::Quaternion rotation = Ogre::Quaternion(mBody->getWorldTransform().getRotation().getW(), mBody->getWorldTransform().getRotation().getX(), mBody->getWorldTransform().getRotation().getY(), mBody->getWorldTransform().getRotation().getZ()); @@ -84,14 +88,18 @@ namespace Physic Ogre::Quaternion PhysicActor::getRotation() { + assert(mBody); btQuaternion quat = mBody->getWorldTransform().getRotation() * mBoxRotationInverse; return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()); } void PhysicActor::setScale(float scale){ //We only need to change the scaled box translation, box rotations remain the same. + assert(mBody); mBoxScaledTranslation = mBoxScaledTranslation / mBody->getCollisionShape()->getLocalScaling().getX(); mBoxScaledTranslation *= scale; + Ogre::Vector3 pos = getPosition(); + Ogre::Quaternion rot = getRotation(); if(mBody){ mEngine->dynamicsWorld->removeRigidBody(mBody); mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody); @@ -99,8 +107,8 @@ namespace Physic delete mRaycastingBody; } //Create the newly scaled rigid body - mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation()); - mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation(), 0, 0, true); + mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot); + mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot, 0, 0, true); mEngine->addRigidBody(mBody, false, mRaycastingBody); //Add rigid body to dynamics world, but do not add to object map } From 6934b20abd7c09ece9469f2be330512d91895982 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 17:57:58 +0100 Subject: [PATCH 260/817] actors are now updates every frame. This should not be the case, but this is a quickfix for AI. --- apps/openmw/mwmechanics/actors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 89671ee08..82e46ea46 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -210,7 +210,7 @@ namespace MWMechanics { mDuration += duration; - if (mDuration>=0.25) + //if (mDuration>=0.25) { float totalDuration = mDuration; mDuration = 0; From 0a187e56aa8331624163789059dee3ca85a25095 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 17:58:11 +0100 Subject: [PATCH 261/817] bugfix --- apps/openmw/mwmechanics/aitravel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 25efe8fff..65d43749b 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -80,9 +80,9 @@ namespace MWMechanics dest.mZ = mZ; ESM::Pathgrid::Point start; - dest.mX = pos.pos[0]; - dest.mY = pos.pos[1]; - dest.mZ = pos.pos[2]; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } From 905cff2a9456406f1be91ca311ab219980e9840c Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 18:02:12 +0100 Subject: [PATCH 262/817] anonymous namespace --- apps/openmw/mwmechanics/aitravel.cpp | 15 +++++++++------ apps/openmw/mwmechanics/pathfinding.cpp | 8 +++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 65d43749b..13ae2a592 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,6 +13,15 @@ #include #include "boost/tuple/tuple.hpp" +namespace +{ + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } +} + namespace MWMechanics { @@ -26,12 +35,6 @@ namespace MWMechanics return new AiTravel(*this); } - static float sgn(float a) - { - if(a>0) return 1.; - else return -1.; - } - bool AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1d98674ef..7c22e5470 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -4,10 +4,9 @@ #include "boost/tuple/tuple.hpp" #include "OgreMath.h" -namespace MWMechanics +namespace { - - //helpers functions + //helpers functions float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); @@ -89,7 +88,10 @@ namespace MWMechanics const PathGridGraph & mGraph; PointID mGoal; }; +} +namespace MWMechanics +{ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; From 23b477a9380c4c6a4f60a2b809ba17a6aa9dc884 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Apr 2013 04:36:28 +0200 Subject: [PATCH 263/817] Fix normal maps with spaces in filename not getting loaded --- components/nifogre/material.cpp | 5 ----- extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp | 9 +++++++++ files/materials/objects.mat | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp index 431b8219a..55f064c55 100644 --- a/components/nifogre/material.cpp +++ b/components/nifogre/material.cpp @@ -333,11 +333,6 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); } - if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) - { - // force automips on normal maps for now - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); - } for(int i = 0;i < 7;i++) { diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp index 4ec43fcae..f45e64155 100644 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp @@ -2,6 +2,8 @@ #include +#include + namespace sh { void OgreMaterialSerializer::reset() @@ -44,6 +46,13 @@ namespace sh bool OgreMaterialSerializer::setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t) { + // quick access to automip setting, without having to use 'texture' which doesn't like spaces in filenames + if (param == "num_mipmaps") + { + t->setNumMipmaps(Ogre::StringConverter::parseInt(value)); + return true; + } + reset(); mScriptContext.section = Ogre::MSS_TEXTUREUNIT; diff --git a/files/materials/objects.mat b/files/materials/objects.mat index b9277914b..8f8734d62 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -55,7 +55,9 @@ material openmw_objects_base texture_unit normalMap { - texture $normalMap + direct_texture $normalMap + // force automips here for now + num_mipmaps 4 } texture_unit emissiveMap From a1ece7de306091c5b7beb834c49b9e34809cae3a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 12 Apr 2013 14:48:53 +0200 Subject: [PATCH 264/817] Bug #613: fixed assert in string literal access function --- components/interpreter/runtime.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index dcf17d255..8814ca7ff 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -34,17 +34,20 @@ namespace Interpreter std::string Runtime::getStringLiteral (int index) const { - assert (index>=0 && index (mCode[3])); + assert (index>=0 && static_cast (mCode[3])>0); const char *literalBlock = reinterpret_cast (mCode + 4 + mCode[0] + mCode[1] + mCode[2]); + int offset = 0; + for (; index; --index) { - literalBlock += std::strlen (literalBlock) + 1; + offset += std::strlen (literalBlock+offset) + 1; + assert (offset/4 (mCode[3])); } - return literalBlock; + return literalBlock+offset; } void Runtime::configure (const Interpreter::Type_Code *code, int codeSize, Context& context) From 5b30677e41f26312a6eb844c65c6169967815471 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Apr 2013 14:37:16 -0700 Subject: [PATCH 265/817] Add the start of a custom gravity affector --- components/nifogre/ogrenifloader.cpp | 15 ++- libs/openengine/ogre/particles.cpp | 181 +++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 11 ++ libs/openengine/ogre/renderer.cpp | 4 + 4 files changed, 207 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 48893bf4a..113fd3d16 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -366,10 +366,21 @@ class NIFObjectLoader if(e->recType == Nif::RC_NiParticleGrowFade) { const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade"); affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } + else if(e->recType == Nif::RC_NiGravity) + { + const Nif::NiGravity *gr = static_cast(e.getPtr()); + + Ogre::ParticleAffector *affector = partsys->addAffector("Gravity"); + affector->setParameter("force", Ogre::StringConverter::toString(gr->mForce)); + affector->setParameter("force_type", (gr->mType==0) ? "wind" : "point"); + affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection)); + affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition)); + } else if(e->recType == Nif::RC_NiParticleRotation) { // TODO: Implement (Ogre::RotationAffector?) @@ -378,10 +389,6 @@ class NIFObjectLoader { // TODO: Implement (Ogre::ColourInterpolatorAffector?) } - else if(e->recType == Nif::RC_NiGravity) - { - // TODO: Implement - } else warn("Unhandled particle modifier "+e->recName); e = e->extra; diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 3453b7f3d..244ca0ec3 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -144,3 +144,184 @@ Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSy mAffectors.push_back(p); return p; } + + +class GravityAffector : public Ogre::ParticleAffector +{ + enum ForceType { + Type_Wind, + Type_Point + }; + +public: + /** Command object for force (see Ogre::ParamCommand).*/ + class CmdForce : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getForce()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setForce(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for force_type (see Ogre::ParamCommand).*/ + class CmdForceType : public Ogre::ParamCommand + { + static ForceType getTypeFromString(const Ogre::String &type) + { + if(type == "wind") + return Type_Wind; + if(type == "point") + return Type_Point; + OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type string: "+type, + "CmdForceType::getTypeFromString"); + } + + static Ogre::String getStringFromType(ForceType type) + { + switch(type) + { + case Type_Wind: return "wind"; + case Type_Point: return "point"; + } + OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type enum: "+Ogre::StringConverter::toString(type), + "CmdForceType::getStringFromType"); + } + + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return getStringFromType(self->getForceType()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setForceType(getTypeFromString(val)); + } + }; + + /** Command object for direction (see Ogre::ParamCommand).*/ + class CmdDirection : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getDirection()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setDirection(Ogre::StringConverter::parseVector3(val)); + } + }; + + /** Command object for position (see Ogre::ParamCommand).*/ + class CmdPosition : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getPosition()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setPosition(Ogre::StringConverter::parseVector3(val)); + } + }; + + + /** Default constructor. */ + GravityAffector(Ogre::ParticleSystem *psys) + : ParticleAffector(psys) + , mForce(0.0f) + , mForceType(Type_Wind) + , mPosition(0.0f) + , mDirection(0.0f) + { + mType = "Gravity"; + + // Init parameters + if(createParamDictionary("GravityAffector")) + { + Ogre::ParamDictionary *dict = getParamDictionary(); + + Ogre::String force_title("force"); + Ogre::String force_descr("Amount of force applied to particles."); + Ogre::String force_type_title("force_type"); + Ogre::String force_type_descr("Type of force applied to particles (point or wind)."); + Ogre::String direction_title("direction"); + Ogre::String direction_descr("Direction of wind forces."); + Ogre::String position_title("position"); + Ogre::String position_descr("Position of point forces."); + + dict->addParameter(Ogre::ParameterDef(force_title, force_descr, Ogre::PT_REAL), &msForceCmd); + dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd); + dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd); + dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd); + } + } + + /** See Ogre::ParticleAffector. */ + void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + } + } + + void setForce(Ogre::Real force) + { mForce = force; } + Ogre::Real getForce() const + { return mForce; } + + void setForceType(ForceType type) + { mForceType = type; } + ForceType getForceType() const + { return mForceType; } + + void setDirection(const Ogre::Vector3 &dir) + { mDirection = dir; } + const Ogre::Vector3 &getDirection() const + { return mDirection; } + + void setPosition(const Ogre::Vector3 &pos) + { mPosition = pos; } + const Ogre::Vector3 &getPosition() const + { return mPosition; } + + static CmdForce msForceCmd; + static CmdForceType msForceTypeCmd; + static CmdDirection msDirectionCmd; + static CmdPosition msPositionCmd; + +protected: + float mForce; + + ForceType mForceType; + + Ogre::Vector3 mPosition; + Ogre::Vector3 mDirection; +}; +GravityAffector::CmdForce GravityAffector::msForceCmd; +GravityAffector::CmdForceType GravityAffector::msForceTypeCmd; +GravityAffector::CmdDirection GravityAffector::msDirectionCmd; +GravityAffector::CmdPosition GravityAffector::msPositionCmd; + +Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleAffector *p = new GravityAffector(psys); + mAffectors.push_back(p); + return p; +} diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp index d466bb030..0d88a348e 100644 --- a/libs/openengine/ogre/particles.hpp +++ b/libs/openengine/ogre/particles.hpp @@ -14,4 +14,15 @@ class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); }; +/** Factory class for GravityAffector. */ +class GravityAffectorFactory : public Ogre::ParticleAffectorFactory +{ + /** See Ogre::ParticleAffectorFactory */ + Ogre::String getName() const + { return "Gravity"; } + + /** See Ogre::ParticleAffectorFactory */ + Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); +}; + #endif /* OENGINE_OGRE_PARTICLES_H */ diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index c9e91968f..fcc4961b5 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -211,6 +211,10 @@ void OgreRenderer::configure(const std::string &logPath, Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); mAffectorFactories.push_back(affector); + affector = OGRE_NEW GravityAffectorFactory(); + Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); + mAffectorFactories.push_back(affector); + RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) From 86bac7aa9201ac54b71de4d76b150d1a95695daf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Apr 2013 23:40:30 +0200 Subject: [PATCH 266/817] Fix wrong BSA group name typo --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 17610e479..118932ade 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -176,7 +176,7 @@ void OMW::Engine::loadBSA() if (mFileCollections.doesExist(*archive)) { // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(dataDirs.size()-i); + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); From 2eb9395661d84bb56603472564b79a0d9a054222 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Apr 2013 00:05:31 +0200 Subject: [PATCH 267/817] Do some padding with zeros on the resource group name to avoid priority problems with more than 10 resource groups. --- apps/openmw/engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 118932ade..69e3cdc53 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -161,7 +161,7 @@ void OMW::Engine::loadBSA() for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { // Last data dir has the highest priority - std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i); + std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0'); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); std::string dataDirectory = iter->string(); @@ -176,7 +176,7 @@ void OMW::Engine::loadBSA() if (mFileCollections.doesExist(*archive)) { // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i); + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i, 8, '0'); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); From d50150ad715d278b42ec2201a0ad7728649db748 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Apr 2013 00:13:56 +0200 Subject: [PATCH 268/817] Scale adjustment factor should not be written back to cellref scale --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 11ccd8f2f..e70aedd55 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -801,8 +801,8 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { - MWWorld::Class::get(ptr).adjustScale(ptr,scale); ptr.getCellRef().mScale = scale; + MWWorld::Class::get(ptr).adjustScale(ptr,scale); if(ptr.getRefData().getBaseNode() == 0) return; From 9cc97b195c1732bd784833452c49baee829b2c8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 13:03:45 -0700 Subject: [PATCH 269/817] Implement Gravity particle affector effects --- libs/openengine/ogre/particles.cpp | 34 +++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 244ca0ec3..61ebddc56 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -274,10 +274,14 @@ public: /** See Ogre::ParticleAffector. */ void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) { - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) + switch(mForceType) { - Ogre::Particle *p = pi.getNext(); + case Type_Wind: + applyWindForce(psys, timeElapsed); + break; + case Type_Point: + applyPointForce(psys, timeElapsed); + break; } } @@ -307,6 +311,30 @@ public: static CmdPosition msPositionCmd; protected: + void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + const Ogre::Vector3 vec = mDirection * mForce * timeElapsed; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + p->direction += vec; + } + } + + void applyPointForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + const Ogre::Real force = mForce * timeElapsed; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + const Ogre::Vector3 vec = (p->position - mPosition).normalisedCopy() * force; + p->direction += vec; + } + } + + float mForce; ForceType mForceType; From 07c24e038212d6b1b3eb52838f9af690b4fa4c00 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 13:13:09 -0700 Subject: [PATCH 270/817] Don't create entities and particles when only the skeleton base is needed --- components/nifogre/ogrenifloader.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 113fd3d16..4e6d3b3c4 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -468,7 +468,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags=0) + ObjectList &objectlist, int flags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -585,8 +585,8 @@ class NIFObjectLoader } } - if(node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles) + if((node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) @@ -614,8 +614,7 @@ class NIFObjectLoader { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all - * other meshes are hidden or entities attached to a specific node - * instead of skinned. */ + * other entities are attached to bones and not skinned. */ Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); if(meshMgr.getByName(name).isNull()) NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); @@ -625,7 +624,7 @@ class NIFObjectLoader } public: - static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) + static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group, int flags=0) { Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); if(nif->numRoots() < 1) @@ -651,7 +650,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist); + createObjects(name, group, sceneMgr, node, objectlist, flags); } }; @@ -739,7 +738,7 @@ ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string na ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(sceneMgr, objectlist, name, group); + NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000); return objectlist; } From 7191f6ed2a7f500b1d51275d8ece011ed9590f8c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 14:36:24 -0700 Subject: [PATCH 271/817] Start a Nif-style particle emitter Not complete yet (doesn't handle the vertical or horizontal direction/angle), and should probably be renamed. --- components/nifogre/ogrenifloader.cpp | 5 +- libs/openengine/ogre/particles.cpp | 217 +++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 13 ++ libs/openengine/ogre/renderer.cpp | 12 ++ libs/openengine/ogre/renderer.hpp | 2 + 5 files changed, 248 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 4e6d3b3c4..d546ca271 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -351,7 +351,7 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { - Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); + Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, @@ -359,6 +359,9 @@ class NIFObjectLoader emitter->setEmissionRate(partctrl->emitRate); emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, partctrl->lifetime+partctrl->lifetimeRandom); + emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); + emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); + emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); Nif::ExtraPtr e = partctrl->extra; while(!e.empty()) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 61ebddc56..a6bc78d5f 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -2,9 +2,226 @@ #include #include +#include #include #include +/* FIXME: "Nif" isn't really an appropriate emitter name. */ +class NifEmitter : public Ogre::ParticleEmitter +{ +public: + /** Command object for the emitter width (see Ogre::ParamCommand).*/ + class CmdWidth : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getWidth()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setWidth(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for the emitter height (see Ogre::ParamCommand).*/ + class CmdHeight : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getHeight()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setHeight(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for the emitter depth (see Ogre::ParamCommand).*/ + class CmdDepth : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getDepth()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setDepth(Ogre::StringConverter::parseReal(val)); + } + }; + + + NifEmitter(Ogre::ParticleSystem *psys) + : Ogre::ParticleEmitter(psys) + { + initDefaults("Nif"); + } + + /** See Ogre::ParticleEmitter. */ + unsigned short _getEmissionCount(Ogre::Real timeElapsed) + { + // Use basic constant emission + return genConstantEmissionCount(timeElapsed); + } + + /** See Ogre::ParticleEmitter. */ + void _initParticle(Ogre::Particle *particle) + { + Ogre::Vector3 xOff, yOff, zOff; + + // Call superclass + ParticleEmitter::_initParticle(particle); + + xOff = Ogre::Math::SymmetricRandom() * mXRange; + yOff = Ogre::Math::SymmetricRandom() * mYRange; + zOff = Ogre::Math::SymmetricRandom() * mZRange; + + particle->position = mPosition + xOff + yOff + zOff; + + // Generate complex data by reference + genEmissionColour(particle->colour); + genEmissionDirection(particle->direction); + genEmissionVelocity(particle->direction); + + // Generate simpler data + particle->timeToLive = particle->totalTimeToLive = genEmissionTTL(); + } + + /** Overloaded to update the trans. matrix */ + void setDirection(const Ogre::Vector3 &dir) + { + ParticleEmitter::setDirection(dir); + genAreaAxes(); + } + + /** Sets the size of the area from which particles are emitted. + @param + size Vector describing the size of the area. The area extends + around the center point by half the x, y and z components of + this vector. The box is aligned such that it's local Z axis points + along it's direction (see setDirection) + */ + void setSize(const Ogre::Vector3 &size) + { + mSize = size; + genAreaAxes(); + } + + /** Sets the size of the area from which particles are emitted. + @param x,y,z + Individual axis lengths describing the size of the area. The area + extends around the center point by half the x, y and z components + of this vector. The box is aligned such that it's local Z axis + points along it's direction (see setDirection) + */ + void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z) + { + mSize.x = x; + mSize.y = y; + mSize.z = z; + genAreaAxes(); + } + + /** Sets the width (local x size) of the emitter. */ + void setWidth(Ogre::Real width) + { + mSize.x = width; + genAreaAxes(); + } + /** Gets the width (local x size) of the emitter. */ + Ogre::Real getWidth(void) const + { return mSize.x; } + /** Sets the height (local y size) of the emitter. */ + void setHeight(Ogre::Real height) + { + mSize.y = height; + genAreaAxes(); + } + /** Gets the height (local y size) of the emitter. */ + Ogre::Real getHeight(void) const + { return mSize.y; } + /** Sets the depth (local y size) of the emitter. */ + void setDepth(Ogre::Real depth) + { + mSize.z = depth; + genAreaAxes(); + } + /** Gets the depth (local y size) of the emitter. */ + Ogre::Real getDepth(void) const + { return mSize.z; } + +protected: + /// Size of the area + Ogre::Vector3 mSize; + + /// Local axes, not normalised, their magnitude reflects area size + Ogre::Vector3 mXRange, mYRange, mZRange; + + /// Internal method for generating the area axes + void genAreaAxes(void) + { + Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); + + mXRange = mLeft * (mSize.x * 0.5f); + mYRange = mUp * (mSize.y * 0.5f); + mZRange = mDirection * (mSize.z * 0.5f); + } + + /** Internal for initializing some defaults and parameters + @return True if custom parameters need initialising + */ + bool initDefaults(const Ogre::String &t) + { + // Defaults + mDirection = Ogre::Vector3::UNIT_Z; + mUp = Ogre::Vector3::UNIT_Y; + setSize(100.0f, 100.0f, 100.0f); + mType = t; + + // Set up parameters + if(createParamDictionary(mType + "Emitter")) + { + addBaseParameters(); + Ogre::ParamDictionary *dict = getParamDictionary(); + + // Custom params + dict->addParameter(Ogre::ParameterDef("width", + "Width of the shape in world coordinates.", + Ogre::PT_REAL), + &msWidthCmd); + dict->addParameter(Ogre::ParameterDef("height", + "Height of the shape in world coordinates.", + Ogre::PT_REAL), + &msHeightCmd); + dict->addParameter(Ogre::ParameterDef("depth", + "Depth of the shape in world coordinates.", + Ogre::PT_REAL), + &msDepthCmd); + + return true; + } + return false; + } + + /// Command objects + static CmdWidth msWidthCmd; + static CmdHeight msHeightCmd; + static CmdDepth msDepthCmd; +}; +NifEmitter::CmdWidth NifEmitter::msWidthCmd; +NifEmitter::CmdHeight NifEmitter::msHeightCmd; +NifEmitter::CmdDepth NifEmitter::msDepthCmd; + +Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleEmitter *emit = OGRE_NEW NifEmitter(psys); + mEmitters.push_back(emit); + return emit; +} + + class GrowFadeAffector : public Ogre::ParticleAffector { public: diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp index 0d88a348e..e1f3fd282 100644 --- a/libs/openengine/ogre/particles.hpp +++ b/libs/openengine/ogre/particles.hpp @@ -1,8 +1,21 @@ #ifndef OENGINE_OGRE_PARTICLES_H #define OENGINE_OGRE_PARTICLES_H +#include #include +/** Factory class for NifEmitter. */ +class NifEmitterFactory : public Ogre::ParticleEmitterFactory +{ +public: + /** See ParticleEmitterFactory */ + Ogre::String getName() const + { return "Nif"; } + + /** See ParticleEmitterFactory */ + Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys); +}; + /** Factory class for GrowFadeAffector. */ class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory { diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index fcc4961b5..7be713796 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -110,6 +110,11 @@ void OgreRenderer::loadPlugins() void OgreRenderer::unloadPlugins() { + std::vector::iterator ei; + for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();ei++) + OGRE_DELETE (*ei); + mEmitterFactories.clear(); + std::vector::iterator ai; for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();ai++) OGRE_DELETE (*ai); @@ -206,6 +211,13 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); + + Ogre::ParticleEmitterFactory *emitter; + emitter = OGRE_NEW NifEmitterFactory(); + Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter); + mEmitterFactories.push_back(emitter); + + Ogre::ParticleAffectorFactory *affector; affector = OGRE_NEW GrowFadeAffectorFactory(); Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index ea46f5ae6..962ae4f2e 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -40,6 +40,7 @@ namespace Ogre class SceneManager; class Camera; class Viewport; + class ParticleEmitterFactory; class ParticleAffectorFactory; } @@ -95,6 +96,7 @@ namespace OEngine Ogre::D3D9Plugin* mD3D9Plugin; #endif Fader* mFader; + std::vector mEmitterFactories; std::vector mAffectorFactories; bool logging; From dd981077b955e8be6123c05765467112b61d5cdc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:16:57 -0700 Subject: [PATCH 272/817] Handle the vertical and horizontal parameters of Nif particles Note that 'horizontal' is mapped to rotate around the Z axis, not Y. The Nif particle parameters seem to be set up to expect a normal OpenGL (Direct3D?) orientation, rather than the 90-degree pitch offset of the game. --- components/nifogre/ogrenifloader.cpp | 10 ++- libs/openengine/ogre/particles.cpp | 125 ++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d546ca271..78b60d712 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -352,16 +352,18 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); - emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, partctrl->velocity+partctrl->velocityRandom); emitter->setEmissionRate(partctrl->emitRate); emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, partctrl->lifetime+partctrl->lifetimeRandom); emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); - emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); - emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); + emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); + emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); + emitter->setParameter("vertical_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalDir).valueDegrees())); + emitter->setParameter("vertical_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalAngle).valueDegrees())); + emitter->setParameter("horizontal_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalDir).valueDegrees())); + emitter->setParameter("horizontal_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalAngle).valueDegrees())); Nif::ExtraPtr e = partctrl->extra; while(!e.empty()) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index a6bc78d5f..5cb92bf0f 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -52,6 +52,70 @@ public: } }; + /** Command object for the emitter vertical_direction (see Ogre::ParamCommand).*/ + class CmdVerticalDir : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getVerticalDirection().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setVerticalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter vertical_angle (see Ogre::ParamCommand).*/ + class CmdVerticalAngle : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getVerticalAngle().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setVerticalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter horizontal_direction (see Ogre::ParamCommand).*/ + class CmdHorizontalDir : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getHorizontalDirection().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setHorizontalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter horizontal_angle (see Ogre::ParamCommand).*/ + class CmdHorizontalAngle : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getHorizontalAngle().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setHorizontalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + NifEmitter(Ogre::ParticleSystem *psys) : Ogre::ParticleEmitter(psys) @@ -82,7 +146,14 @@ public: // Generate complex data by reference genEmissionColour(particle->colour); - genEmissionDirection(particle->direction); + + // NOTE: We do not use mDirection/mAngle for the initial direction. + Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); + Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); + particle->direction = (Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X) * + Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z)) * + Ogre::Vector3::UNIT_Z; + genEmissionVelocity(particle->direction); // Generate simpler data @@ -152,10 +223,36 @@ public: Ogre::Real getDepth(void) const { return mSize.z; } + void setVerticalDirection(Ogre::Radian vdir) + { mVerticalDir = vdir; } + Ogre::Radian getVerticalDirection(void) const + { return mVerticalDir; } + + void setVerticalAngle(Ogre::Radian vangle) + { mVerticalAngle = vangle; } + Ogre::Radian getVerticalAngle(void) const + { return mVerticalAngle; } + + void setHorizontalDirection(Ogre::Radian hdir) + { mHorizontalDir = hdir; } + Ogre::Radian getHorizontalDirection(void) const + { return mHorizontalDir; } + + void setHorizontalAngle(Ogre::Radian hangle) + { mHorizontalAngle = hangle; } + Ogre::Radian getHorizontalAngle(void) const + { return mHorizontalAngle; } + + protected: /// Size of the area Ogre::Vector3 mSize; + Ogre::Radian mVerticalDir; + Ogre::Radian mVerticalAngle; + Ogre::Radian mHorizontalDir; + Ogre::Radian mHorizontalAngle; + /// Local axes, not normalised, their magnitude reflects area size Ogre::Vector3 mXRange, mYRange, mZRange; @@ -163,7 +260,6 @@ protected: void genAreaAxes(void) { Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); - mXRange = mLeft * (mSize.x * 0.5f); mYRange = mUp * (mSize.y * 0.5f); mZRange = mDirection * (mSize.z * 0.5f); @@ -200,6 +296,23 @@ protected: Ogre::PT_REAL), &msDepthCmd); + dict->addParameter(Ogre::ParameterDef("vertical_direction", + "Vertical direction of emitted particles (in degrees).", + Ogre::PT_REAL), + &msVerticalDirCmd); + dict->addParameter(Ogre::ParameterDef("vertical_angle", + "Vertical direction variance of emitted particles (in degrees).", + Ogre::PT_REAL), + &msVerticalAngleCmd); + dict->addParameter(Ogre::ParameterDef("horizontal_direction", + "Horizontal direction of emitted particles (in degrees).", + Ogre::PT_REAL), + &msHorizontalDirCmd); + dict->addParameter(Ogre::ParameterDef("horizontal_angle", + "Horizontal direction variance of emitted particles (in degrees).", + Ogre::PT_REAL), + &msHorizontalAngleCmd); + return true; } return false; @@ -209,10 +322,18 @@ protected: static CmdWidth msWidthCmd; static CmdHeight msHeightCmd; static CmdDepth msDepthCmd; + static CmdVerticalDir msVerticalDirCmd; + static CmdVerticalAngle msVerticalAngleCmd; + static CmdHorizontalDir msHorizontalDirCmd; + static CmdHorizontalAngle msHorizontalAngleCmd; }; NifEmitter::CmdWidth NifEmitter::msWidthCmd; NifEmitter::CmdHeight NifEmitter::msHeightCmd; NifEmitter::CmdDepth NifEmitter::msDepthCmd; +NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd; +NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd; +NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd; +NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd; Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) { From 80a4345787d71d60e7d202bd1898ce2b5e4694ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:26:34 -0700 Subject: [PATCH 273/817] Keep particles in local space --- components/nifogre/ogrenifloader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 78b60d712..40730a586 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -436,6 +436,9 @@ class NIFObjectLoader particledata->particleRadius*2.0f); partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); + // TODO: There is probably a field or flag to specify this, as some + // particle effects have it and some don't. + partsys->setKeepParticlesInLocalSpace(true); Nif::ControllerPtr ctrl = partnode->controller; while(!ctrl.empty()) From 0b363ba36e41e28bf3193e5774533218e68e6fa6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:42:32 -0700 Subject: [PATCH 274/817] Handle NiParticleColorModifier with Ogre's ColourInterpolator Note that Ogre's ColourInterpolator has a maximum of six color stages. This seems to be fine so far, but if we want anything better, we'll need a custom affector for it. --- components/nifogre/ogrenifloader.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 40730a586..a26f43131 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -386,14 +386,30 @@ class NIFObjectLoader affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection)); affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition)); } + else if(e->recType == Nif::RC_NiParticleColorModifier) + { + const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiColorData *clrdata = cl->data.getPtr(); + + Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator"); + size_t num_colors = std::min(6, clrdata->mKeyList.mKeys.size()); + for(size_t i = 0;i < num_colors;i++) + { + Ogre::ColourValue color; + color.r = clrdata->mKeyList.mKeys[i].mValue[0]; + color.g = clrdata->mKeyList.mKeys[i].mValue[1]; + color.b = clrdata->mKeyList.mKeys[i].mValue[2]; + color.a = clrdata->mKeyList.mKeys[i].mValue[3]; + affector->setParameter("colour"+Ogre::StringConverter::toString(i), + Ogre::StringConverter::toString(color)); + affector->setParameter("time"+Ogre::StringConverter::toString(i), + Ogre::StringConverter::toString(clrdata->mKeyList.mKeys[i].mTime)); + } + } else if(e->recType == Nif::RC_NiParticleRotation) { // TODO: Implement (Ogre::RotationAffector?) } - else if(e->recType == Nif::RC_NiParticleColorModifier) - { - // TODO: Implement (Ogre::ColourInterpolatorAffector?) - } else warn("Unhandled particle modifier "+e->recName); e = e->extra; From 254c6840d817abd9b8b2c7428a8c1f359316ec0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 18:22:30 -0700 Subject: [PATCH 275/817] Fix particle direction --- libs/openengine/ogre/particles.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 5cb92bf0f..707bd75e0 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -148,10 +148,10 @@ public: genEmissionColour(particle->colour); // NOTE: We do not use mDirection/mAngle for the initial direction. - Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); - particle->direction = (Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X) * - Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z)) * + Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); + particle->direction = (Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) * + Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) * Ogre::Vector3::UNIT_Z; genEmissionVelocity(particle->direction); From acb1b5f0025a01e827a18159aeef9a95cbbebdf4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 22:54:32 -0700 Subject: [PATCH 276/817] Try to handle NiBSAnimationNode This is still incomplete guess work. Currently it seems as though flag 0x20 specifies whether the controllers auto-play (if on), rather than follow the object's animation time. --- components/nifogre/ogrenifloader.cpp | 26 ++++++++++++++++---------- components/nifogre/skeleton.cpp | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a26f43131..ec53b79aa 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -492,7 +492,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags) + ObjectList &objectlist, int flags, int animflags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -503,7 +503,10 @@ class NIFObjectLoader if (node->name.find("marker") != std::string::npos) return; - flags |= node->flags; + if(node->recType == Nif::RC_NiBSAnimationNode) + animflags |= node->flags; + else + flags |= node->flags; Nif::ExtraPtr e = node->extra; while(!e.empty()) @@ -539,9 +542,10 @@ class NIFObjectLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, false)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -552,9 +556,10 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -599,9 +604,10 @@ class NIFObjectLoader const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, true)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -627,7 +633,7 @@ class NIFObjectLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags); } } } @@ -674,7 +680,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist, flags); + createObjects(name, group, sceneMgr, node, objectlist, flags, 0); } }; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index e97e91ef0..28df4894d 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -164,6 +164,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles From f4695ec4ac487812b2b9120e1ebd90726ba9fd58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 00:06:40 -0700 Subject: [PATCH 277/817] Cleanup NIFObjectLoader some --- components/nifogre/ogrenifloader.cpp | 213 +++++++++++++-------------- 1 file changed, 106 insertions(+), 107 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index ec53b79aa..631d39728 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -331,9 +331,9 @@ public: -/** Manual resource loader for NIF objects (meshes, particle systems, etc). - * This is the main class responsible for translating the internal NIF - * structures into something Ogre can use. +/** Object creator for NIFs. This is the main class responsible for creating + * "live" Ogre objects (entities, particle systems, controllers, etc) from + * their NIF equivalents. */ class NIFObjectLoader { @@ -349,6 +349,57 @@ class NIFObjectLoader } + static void createEntity(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, ObjectList &objectlist, + const Nif::Node *node, int flags, int animflags) + { + const Nif::NiTriShape *shape = static_cast(node); + + std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); + if(shape->name.length() > 0) + fullname += "@shape="+shape->name; + Misc::StringUtils::toLower(fullname); + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + if(meshMgr.getByName(fullname).isNull()) + NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); + + Ogre::Entity *entity = sceneMgr->createEntity(fullname); + entity->setVisible(!(flags&0x01)); + + objectlist.mEntities.push_back(entity); + if(objectlist.mSkelBase) + { + if(entity->hasSkeleton()) + entity->shareSkeletonInstanceWith(objectlist.mSkelBase); + else + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + } + } + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); + + const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } + } + + static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); @@ -416,9 +467,9 @@ class NIFObjectLoader } } - static Ogre::ParticleSystem *createParticleSystem(const std::string &name, const std::string &group, - Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, - const Nif::Node *partnode) + static void createParticleSystem(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, ObjectList &objectlist, + const Nif::Node *partnode, int flags, int animflags) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -426,67 +477,63 @@ class NIFObjectLoader else if(partnode->recType == Nif::RC_NiRotatingParticles) particledata = static_cast(partnode)->data.getPtr(); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); - try { - std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - bool needTangents = false; + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; + bool needTangents = false; - partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, needTangents)); + partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + wireprop, needTangents)); - partsys->setDefaultDimensions(particledata->particleRadius*2.0f, - particledata->particleRadius*2.0f); - partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->numParticles); - // TODO: There is probably a field or flag to specify this, as some - // particle effects have it and some don't. - partsys->setKeepParticlesInLocalSpace(true); + partsys->setDefaultDimensions(particledata->particleRadius*2.0f, + particledata->particleRadius*2.0f); + partsys->setCullIndividually(false); + partsys->setParticleQuota(particledata->numParticles); + // TODO: There is probably a field or flag to specify this, as some + // particle effects have it and some don't. + partsys->setKeepParticlesInLocalSpace(true); - Nif::ControllerPtr ctrl = partnode->controller; - while(!ctrl.empty()) + Nif::ControllerPtr ctrl = partnode->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiParticleSystemController) { - if(ctrl->recType == Nif::RC_NiParticleSystemController) + const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); + + createParticleEmitterAffectors(partsys, partctrl); + if(!partctrl->emitter.empty() && !partsys->isAttached()) { - const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); - - createParticleEmitterAffectors(partsys, partctrl); - if(!partctrl->emitter.empty() && !partsys->isAttached()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); - Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); - entitybase->attachObjectToBone(trgtbone->getName(), partsys); - } + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - ctrl = ctrl->next; - } - - if(!partsys->isAttached()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); - Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); - entitybase->attachObjectToBone(trgtbone->getName(), partsys); } + ctrl = ctrl->next; } - catch(std::exception &e) { - std::cerr<< "Particles exception: "<destroyParticleSystem(partsys); - partsys = NULL; - }; - return partsys; + + if(!partsys->isAttached()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); + } + + partsys->setVisible(!(flags&0x01)); + objectlist.mParticles.push_back(partsys); } @@ -569,61 +616,13 @@ class NIFObjectLoader if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { - const Nif::NiTriShape *shape = static_cast(node); - - std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(shape->name.length() > 0) - fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - if(meshMgr.getByName(fullname).isNull()) - NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - - Ogre::Entity *entity = sceneMgr->createEntity(fullname); - entity->setVisible(!(flags&0x01)); - - objectlist.mEntities.push_back(entity); - if(objectlist.mSkelBase) - { - if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(objectlist.mSkelBase); - else - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); - } - } - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiUVController) - { - const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); - - const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - ctrl = ctrl->next; - } + createEntity(name, group, sceneMgr, objectlist, node, flags, animflags); } if((node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { - Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); - if(partsys != NULL) - { - partsys->setVisible(!(flags&0x01)); - objectlist.mParticles.push_back(partsys); - } + createParticleSystem(name, group, sceneMgr, objectlist, node, flags, animflags); } const Nif::NiNode *ninode = dynamic_cast(node); From 03af0a8ac972ca22a4f918523cd1be2ff28579a4 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 14 Apr 2013 10:02:48 +0200 Subject: [PATCH 278/817] Adding more icons from nomadic1, replacing older with recently redoned. --- files/opencs/raster/apparatus.png | Bin 1580 -> 1440 bytes files/opencs/raster/armor.png | Bin 1908 -> 1641 bytes files/opencs/raster/clothing.png | Bin 0 -> 1377 bytes files/opencs/raster/container.png | Bin 1570 -> 1526 bytes files/opencs/raster/creature.png | Bin 2506 -> 2297 bytes files/opencs/raster/door.png | Bin 1715 -> 1627 bytes files/opencs/raster/leveled-creature.png | Bin 2212 -> 2150 bytes files/opencs/raster/lockpick.png | Bin 679 -> 671 bytes files/opencs/raster/miscellaneous.png | Bin 1518 -> 1716 bytes files/opencs/raster/npc.png | Bin 0 -> 2143 bytes files/opencs/raster/potion.png | Bin 1876 -> 1582 bytes files/opencs/raster/probe.png | Bin 583 -> 587 bytes files/opencs/raster/random-item.png | Bin 1993 -> 1698 bytes files/opencs/raster/repair.png | Bin 1280 -> 1115 bytes files/opencs/raster/weapon.png | Bin 1064 -> 1003 bytes 15 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 files/opencs/raster/clothing.png create mode 100644 files/opencs/raster/npc.png diff --git a/files/opencs/raster/apparatus.png b/files/opencs/raster/apparatus.png index 037ed290fe9d5fd538bd21f9eda35f83d5048069..3cef537e140428563f908eeeb08214999255a7ae 100644 GIT binary patch delta 1333 zcmV-51o#`6*S5$qSxE`z8{Nkkw-N+OVi)D;p| z10ewfLCpQfH z0EB@8Uq-o9PJ>})T>!$fwE20$%{?CGh(n>X`#@nR6Uxtc!?NrVbd1;L{LzPWTM zeRXAJk^&gQ#6%0iLW5R4761!6aXfsHg)c0Oz~N|u!H|#8P~k;S1i>kuGPcjm{D!5a zag2=I#qe-FX@4Q;wZ{TDDDrEtTI;90oTxPCnc60yJAtH4!2A_-JnyLOJI zz(Or(hsAOWeSK9pBnfbP6`*thrl zcf1r`G=H#w(D^ zgBYGpt74qa2@cLMb^_YCjW|DV#j|G?%+2+4H-BP!+Dt$b0lNv<$xVyh-b%oG1Z*N; z0|D>Q1l>k|e+>a|5zs(dszg^;1+}ys9UY};Yb!xZiyn1#1(3^x3{R_7GAk<%4n8x} ziN}vSNQiCRN*)_)roGVUT26z5w_&x`aAVrvZ$NMFO-`^T({;+KjMGg=M=@GkuM*@J zG=DV}p`qa-?%XLLU><5~&%u7FE39=a4_G=9irJ;_7FMT-t!OPrKM>Q z2)yk)azF-?=_XZRf|T9tHouJpz{?mHh4jvN1-{AATbRT-nPo80X z{vIQHQqAU@pS|0+gUe+B*zL8;xY_7_6af29q*koy$%=jMVc8CT`LddPLj?T%yw_O9 zmKBJQ2S>ATo2`XTZ3q3^=+w4wr+;+2tF|4ytSlY%^#ybRbC8%QMS%a_=q&>{C=w|0 z^OHG4(brc);4-phC3If(Tb|T^%e=T)2UdJnt|Zd{|@kHx;t7lw{o^k&$tNY}+xUr7j&M%XS!A rt%56iQj(0zT&)g=&%SThH*4Te9}Z4R0o|-~U&`C+KHrRtf@m)$ z59jThv)0*r?X~vD`*PK)FJytDX`?Z8PN@)=1K@e`@Pd_+@_(|jo#^d7iNr+xo3M2< zACD3U3=q{fHs)h?b{J>R7D1(wj(C&+wIC%gF9UOPxA5?x1Ift|e<_t>v!_V#hyXt= zEoOFnybI5tPrzy|geq7v>oEchNT*Xw+iW#dh5NX5s{`A&n-Q$^FZ2WnPVw~O5vGIb z=~3LjZ$o{3E`L=){D;Q~1j$6!;^Hhkc;LX~{xk4LEUP7ZLDtdleQ<$Do)0+1`GPsxXM5p(b3q^c&LCBOwbExU~w41VTb2 zlhxJPxO1l$*REM{^kMp!J7uxyOL#-wm0Z7^WNdOgTbW|{+j7k_I6^Nu05g|u-co4!3G8puM(CY%AqodVIq0va7R*S*+ zUGth}GJk1ZmoHb4`uk`EdvNbwH<&5izTJtjv387(UcksmD+%-*wdO1dvTeUopzI==qFCLOBK7YWoXA^k(^e$#*Zj(ohVQOj=k00OU zCS`JRhzJi5VFwYm5#e4Ue1!;i5#dfE+>Yzl+epyoiL@2{{mnGqjYPVENY^1R?>i_J z0v9iy2-s}Z9JtfjLl<{rV&W3+-t8bkUL`tfM?JsBGCr|#0oSco22N8jAgL00EkoDZ@ zyz17nzXd;j{1;?rZ-7+lJ;wzR>&?u}?|&q)>u&4$yWr*JKOrkC0z%0fpS({B3F^&2trJGGk+%|9^YV zR|03R4+|53&-dc?&c!ei`}xE=I zUh@oN#R`Okh&M5Cmgx@1X^PHziq2Zf{w6L`ySuBFrP_zUD=T-QrX~kfRe#ysa?7lj zJw~JPg-GbNX+;8o0erK?qNO-JMoTGs@$zMYUC!FW=K08x?{WC>HZXM;7H;7{^7A*L zxOf}bL>)Z11qTkKbJ@RhX97Y)*TQG*>i2&8mT5pL@qLq;szVCxf)razs7{>h*_9wWnOJvFr3O&&lN)Zrfi=u@& z4^wPaD9}PVltX|Z5+o=G!2?@1BMuDNKCrk50#iXI1Uvu&3d%{Gz!0&Mz_sUY(n>kL z?>>;wzK7p+U(bE&HUQfKl*;PNj0|L0t+1x2BRwq*X{o75O@B#2ip2s;ax#*Wl8|IJ z!)!9al$eObgajnS$0OcogfT7-aj~(`pF9a~`4RYr=0LhP8mtAV}E%4`ZY#IM)30GOZ4>g;JB$0MYk4ESZl-Cnt9~@G>5DoW{`g6Z&)r( z!CX3y_>xfs>+izNUE(TWU|;~t%gav4#KeRPWO#TOFJ8RB;NT#hKYxzCzCQH!_TuT& zr+EDMF=PQcSjt8i>>s3DnufV-3JDh`5O;nQrwT`KGJk&v$8-B}H2WF$#QXubUEYwJ{r&w|T3T|xu)Dh(U0q#x^ym>fIy%ta-i`+k9^l@+duVNKMRRjAnwpw$=gu9d zBTqqdx)sssqtK-c<3REN_M3a5P3VEz*om++?bv(jPkZD9S028F9jgUUG>eOi_GtLP zL&Cp9=zoa@&T!TD4J=Q-g~x7TgEI&GnFD0yr%#`F!42`}pweC81^-5R2-eJe_;`C) ze-_~9S51-IY&Ooen=N?=imu`X_f*8-SWFx)U%m`)fxuM&+5Yk4M^0yM%`S$Izn&Ld zuqV|CudJ+e72u~(R8zuH32v2e6_wW@2{QAB?|;=Cu}4nuii!#dRysfeDBG$2H_LW{ zd&_jZ;L?5NP$;Uy&{@bdIr;Q$jrkutF;l+DS-Y74Gn!orTFH}8-KfisKX{G4_0!HoZ#+~=q=%eg@uqxrLTzT zB0#IvUazaG!|3QJtXW08;X8dIpg(QiG;)HcvwcG$mtS8afGjcS^|riom9Ug>PdJL) zCny<5kH>BaFDNL0My+<*@8SS`@Kb5~0wZ%#@%tiTi^ew{sZ{3#_hOq)FuVYAWf&)TettgG;o&xR{%#uzpbNW& z>i0TJw_N~jGOL#f2V5L+0SeUt&hX4kwjZvFevJe4g+#8=dMQpU6FmFJS?o9c<=kXe z!aaQgIm7ev@(`#}%}FH^m+03OK!0Dld#OhJ4qk(aEs@6JQG^&8;egAde}<25xV@v% zR9oHQsLmisuXTEC_WR$p}U2v}0b-ep_t1P*6DvnL$EJ%nmra4TE& z8GK?r_=XP91)(%VOSQe<)Xs8Y3_42}cDT#fI+epY@|>I;$Yrwk60vxV^?zGBKsR^_ z_td+KqoIy#fkt1Cic42eRaM2wc7n4#<6o9|_MXq%0mlQoJYY#N;G6}} zjjVqg*}$5k=o=dw?ILPwYI$6;of1yP%55v#H*G|lS;kgrF)%oOZ4-fHHw*PMd^dK8rUx-AaX01kJBR5J*OTiWz8~dTrOxO6pc^$#(7mLN> mNan}{{fUIaNWNgl{r>?ZwZ|wDcoXCR0000Lx delta 1806 zcmV+p2l4pn4D=3=dw&MwNklE*K}A7_D%3jer7Qv#!7?%mg3)T9zUR&m!LTI#gPD*w z$?rMOIrp4%*8x~3vA3^Eh>u5nTpZ$JV-Xt@gXrjJL`6j*GJi4>5fKpx4-ZFJSQtV> zLlF`Zg5cm_D3wYC1qDG77>K}t0Qh)&!`NaE_~Ll*M6ocoiH4Cd5{ANX7+8m5vsExQ zSq5RFMIbgAS`HF>-GYG2moKBcyBpW8UBlI@SJBzoiA$F*p`)V%7cN{tOG^vRojZr- z=4PBZa|WkRpMOSueLZSxYf)2EgUZTESli0s9MlabWe*$_U62G^hMj*qM7}K$%9~)d zw*i7(r(oz_j!jz@39z@btGamcA|5_`h$l~;u)opKQH+d?V0d^K0|Nu-@9)Q>N00E} z!2{g8cMo^&+`;YJw{h#%E%f&GLh2rhs3YTuQ%xf}?|&I04v!-wX9Pi+0|-ce2%iIY zAxrLqqp}qSZpX24i^T^ANI-jgJNx1J`FXs5{~qt&y~EqLZ=qJJ@%r^^%+1YVc6Jss zGc$Pc;svIsr}6yxb4*Q5K_0jt#b@8(yH4Ol+dn93RwK7=4mm%)#8=-=V_(@65(+1v z%o>1H(SM9hPPy1eVYed-e?X@84e%WnW((Zrr$mo}M0DzkZ#i z>&lfY*t*>po-w@$I5Y{r^e0@T!|+P$$DWk?*q!)0cE;a?N6d9>i{d^T-od4$0S4wC zFy;x`G&NvnYg={x{CQ?6ML97sp%XkbIvYD8uYc(bcL`~MsbdP1p)oKsHLcPJu;m1t zJ$shr^X1Ez7#|}E)lDa0XlO{Q+8Y|rF}Pp)xK7nh1!w151EEx|ftQt)AwNGKiHV6z z1&BBS)Y0f@O-@d-# zr*y8LK7Go%-oiPj7Huio39o&FI!ErHXoRU~4=XsbogycAad9z@965qmZr&^r;OgR% zn4O&s>V|`ZgBTkdV`2#Ix+4Z&sekGPH@4o3d{wa)ys)qkSy@?-%jK{zH&4{`fqzfe zuU}77jRwr!yLVY3(m-}BD{jvZr1(9yv`O-zjddg1Kk zG*(?*&8(+1_y?uHBcfX`IA5B$Dm*VQkJ)c75R4IXi2ye@w;HNY>WG;+1xQj2=?9m@ zA~Z5-#mEVsk&yv^e}7n7Sk!0x$BpUmdI6(i{h+Y5S36+rVA4XpN98`_-D^4{H+_M0lUJ+};smK)y z1r4Da3(;!{Fc)r>@oXa4CKH%3gu*5@VsamAjZ_VM=W&Q7?rXviA3lsYZhzggx3^ad z1Onp~1<(USQG{F82NbBFDWt!PC>z5y0(?A4jj{ z0KFlwa*-LBd;M!6tA{Mr=b57Mx1xL0MJSiy&o}Ql6 z`DzziuXPGOez?I<{C z>^#piHa@f(eAN^z{vx-%s2m*~)wD`cyQY~zH>j?zE}T4hQd4jX zwo~M~z;zZtAGEfzN`K_q=nUN#sizkd6lkt#RP8A#DXidx*48s?*}iHcTFo-aNyIHBZGPx#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000EgNkl6%`P1L7nMHCCES#qK*i-RU0vC-3CExWf8+FvNUAT+>peiV2ffU0feXL z-kDH>XuwRzFMfFEW_j=XJkL4Ld(H_15cWCOX9Z`4e(Qyn8+Mw6B;OJ2;wumI2l;l*+YD5AE z2>6NN5{cZZ*Ei$Ut9i`K%wu+T9$xP(-oEu>WW(trlra>Dpl@*__&0@ z^70xa2$Im%H2|yC1+&?Ku`xS_hMuFR$An|Y>LK7KTO%W)10uo^_AS{|?jBv!s3oFJ8QX-ToRj+Y}x@9zjNi61xibqO7bMq#F4u_DKZvP>%@~M&pGg(9y1JvF(UK_ zIy*=3=+OweyN&d_5gi>vXllBPjp3Vp(a}6@Sb`vVyrkp@0&-wsVG&bPbEJ6YgWx99 zpD-HTlxG*Ib&xtc0ozFNvsJ;{+lTP*;UFG77(iRwAdwlywQKi~m8nL=H&NqZlymXH z1BZPD`GuI9dk44s{{g>$zYq8B^->yoAeAVPowd!!ixr4D4@ksvLuqLR+S@xR0^aw+ z?sEN2X?Xd`%KhLiE!||s2B_5qh~o(iOO=o{1YMsu+w<}{w>zEFoZ1ZDk0BPzAxsg!Su&yjZYCv(v{jWSP+NNv4#z9BwsavcuWlE`@0o%7?z z&q1NcnXa$D3>Lho=pfym5=2GDX#KbWbs#Yz#VrzvA(JURN@Y$B%kuK&I~4v2a=&|B zhGUg$wP(SeAreVy5)*_TUMwGxkumP&1u1|4Z3vI!@pG4N(CKbd_&qS0Tx)i_KkT)& zXXvQ^+WqEDk-3{TM!a8$K31zQUAjr(e?bOxtm&$)G+eM*BWOFmc<~06RTml19`v5C zG+cFceLw_)_JY+mT)1$Zs+@x>u`4Uw@*=Ym{LY<6sH&<9oxu6?*C_mUGT`%o@)`{M z)~yayR-Ou-z`1i*Df~7vpmnLXuLbKf%*>RQ2@np$aCsR^Ax-KmS5`p(Ybb%E=2ckyFsb?5}t>h0LK?-2Ix zIf&xo11R2Ig55>?sj=+Gu3h`M(X6mw4+_|oU(AhXJ8A9MQ3RDLCv*Zd&3dx3zGrBH zVKP%kY_XU^eiTwU9wC@CRH&~iIS0s6$}j=o{&p%umeK< jKWHxq6(HFAUkLmQ{#pGRx(|VW00000NkvXXu0mjfLUWRt literal 0 HcmV?d00001 diff --git a/files/opencs/raster/container.png b/files/opencs/raster/container.png index 7874606ab9b905dd3afc5e58b929e586241f3fd5..2a6ed01eb9969129cbf9edd6d0f404464f97cc92 100644 GIT binary patch delta 1450 zcmV;b1y%Z@4E76Mh z**CI~1%e47Aqjy1fv`g&5y1!%L=ccLQc7uQ-55rzLls-5YOP!C;&f_dI&EM z>K!I7ln%wg1xDMa_hp6-wOKCE4|nn*_r1U8JnwnWIqxa}tD-#td$QeYl8<-gr%=Is z9o2uCr=zy!YN>XohHA^vP_5Z&s>PwEnzNFrO?DO4WK&U%Rwd=uiO0RGW%gL#j|wM? z{Z`fa=^dqbd7uF=M%pkp(vD|`wqWMqW=sz?VQSw-Ozx@2#GoG!cGqJ3-8J~Nrvw+9 zY{=J$##SsKJ}xd-#$!)^w9bsV!$CYh`Z|9e57uC6z=z45)p)qwgZurJ81E~`z1~vX z-sZ-xq7;ZZtZA}##R3*S5U{C2PxfuVvtw^!@+~(W^%f%3Hd z$1M)5F~~x(zzhG!+yXj^*D4K3LvIwO%o5w5p4uK2e!V3N%{Jw1zFIg$*2WSNQ2>8g zT&$Ol)>)J@SGKzFgx+@opFY$cF>(UG+HAws%?=##tVW4WJY!ezN23XeC?HoW9>3Dz z#M1-Kcz$}vJe(xl{a$xi+ZW)M8m+iMKi6r|ms_1USegoxlsg{DiLe4Z>GHnw%~_Z| z(T~|PyYcu?8z%b8V@6KkV*v}kt2cjR)SrRT4Q8D8o3Y!ahC{*c3nwD1fHmpzYb4WdqO)9E!!8{zBuw%;is$g zC`=ZFJsDvgAQg@jnduLMOSU~6{CGtQ%C$m@u>&1W&7-NIO_&;PkC||>A}4?Fk4tqZ z(+HRga2N!CZCkIxiT4~Jzg@LTbk-=);gh4yn}pUX88%nQu&GRn#u5nvMPk$!ir{w% zQI{vcIwv1%vw5h_;=ya>qRPU7PMYv1V+UG2$`@0YD=~Gw8h20H@XN7G{B+oi8y}c( z^?(r<_Z#s2o-~XOq~hET9nOEgt-)u#YMkm;;gg^ON7|Dx(jvofqXa|sBJ8abz?I5= z!B{|@TlVs|AIk9i70>?yA6(0WUCnyQSU{jeKKEd>2oo17R~$Kk@APt!tzpeE7T~ss zX6}9N#3b#&N^D<%zf+NjG-<*NV*v#w;lo=;Gcj?oYT0|f7~WURf?j_T|B$hO+!WzJ ztyP9#sR6Bd$!K=S(Ug^hjdmFVRw?Q;rSMxMsLK$e)+9!aQ3Rhsi0U)}ym|quQu(OR z@#wS9MX8#D961|$VZs1o0d)6@>vpPfyU&XoTMPcF?U9NMIp>FqH5hTLG3-*|{X8Z1 zI~CaLNWvg3+LO!!`6hp30pvwbnlyAX=*G>iqWQ+MT=*`l1U5-x!~rE@J1)?Ou3c`S zC!Fr$6~VWg#V`ulVH*(%G@^hUmEh#r+6>(4DaF@xXItoMq_HfN*J!qr$O*j1D1@HR zI=Q5IfV^CmBKGZZYjLB~g>Tkp%(v8~!uw4kG|-7?7P5Rx7C?W-D1W+a_5wYaeA{4I z7QD|WK%Rs>yR4CnD0XXvcgR#TMo&6Rv7JOt;5})4m;?!Tq79}|r((ODH}-|kfJ;r5 z`IgFL&lkhHQ@PM`6GoRUfXs0N`N{O0myYA*+KA_TA>m$yuT!v*!i^6*3o^PFkmAu` zl;T{C9-mfe!xn#;NbsPJ1D7}y_Xp}irIi4zMtN^_nhy1-#y>GV*rft7KKJO zJ+w41Yg6QplH*C@~57Vxy2RiV*UJBnrZXd>)CJ1|gpm!uF+wGU>kd z_XtG!kF5C78H*pPW6)h?!S!WkTwNNCON*m$aX}=`&o|-B zya?>imm^WbUKuq3nN*ssm2*#9vN+scnSj6AO7X|85^B#W^b zVWQou?a~)i_D8J+_^B@0t?U&1SeXHfW5q8L)a-7$))x_v1nA;ao%lj=l=%74*-G4U z#^HWr_JHiymw(5;Rr5jcu2MY?mxN)HokLnE``n@wUGPT4BLSOM+;^f}g`3r8++CA8 zkokknx#)2w_yqs9NQVOjq1czJMt!mvCWWZalM-$TOw)_%4-^LDmpU7sv=$CD+#OQ) zYs)NtgLmYGU~jGld#0=5jA39=u=VapxFwLOXS;7KGk?O>lmi#Z`bJfZ*P0K?KA8FI z;B8qdY_ZEIfo{JE)MUP|w!YzTL%ZFR?5~42PYFi6Vi*K$QQW^b_9o%?9tXM) zq~YSu1b>`sjmPQcI2_v;i>?L>4y}*I!B3;mQ5T8!8Y8}RMqpQ!0oy9|*s@56rum_0 zbcCROwi;`TRR~iA{^Pd-Qa|*tpNKVX%?f08Ns#)@^ zXO9(+FPGr{Y2tn(l%0Y%mMBn@$w3z+dgeEQlt{^=t_ITpc;C7F5!HMU{4?UH6=Xbz z%6~+U{3ejB7d1FjIcy@H-db+N+Ds)@PgUUKbUAA6!Kg_IhBG+`)ixQb5@o2gO0gu4 z!$OM$@0lf-7a0hLQH-*1F=iP=NLLD=ld=td6Cl$|y4)(p@wrA^T`?J*v-I$0GW47` zCCkuglVU>xhxJwo*2D(l6N?zDq6h)SB!AF7{U$(vv}+j`HJMA*@iZiG zj5tp2c_RULMhG!SGag!w=^WO5fc~7MVH~yb3=S5D;nc!Nd_knAQ;iN5Up1$)Q-AOe z3<1av8V8*uz%gtB^cqzh&h&phLxW=##Org^!v=p}CqSHZV*iM)WR!7&is{{vA;*z& zJ=$k#hLt%5UlcMC+CX8iw~MLQTd`TeUimyJ5c`X?=qL>FdemN*oq{jbPQontSg0lJ zh0zeG|IjQ%+jJG_1&zmZ?hbsBW`824a$}(iWZd2b{dyNr^T^i)U~5`1_7|$KDMj{{ z$#?=^pqc=)c!Ea*@{0idDMl`IZJ5lF9#CMbUHXQ@c>{OI$3ZO)@cBaW`7$yFvsY?K z8HU=cH}DF@c+8Z%1BI9w{o~XSBw7_6EOc3d1bnniz(%-LW>@)on*9d>L!A~ne4Tdy0000%Q(MegORbpU8XO=iTT3LuXm1Ht5nAN^LO^GK> zrS#)kXv5t~Gk-SfPSFn;M`Y-j7t2n*nuvS5^`3+n-i8;^nVr`aGN|g^OLbjB|;*XvCS(0 zs(h8P;%C3EcGB=iD+=(mxfH{Ttmv;uCGVqcQ=}S4 zlf$t`BS8W;@Uo{i-Vvcq7Q(ZKhfe%lXQKn4GVgO5Fi>T}V6~ZsQ<*XzdSx$eW&Qz9{!ypmRWj~)DgVtCf zRP2C$Px1K_A@#CYA?P}vuXV!*tI}am#n39L2nEvfC?11$Y+b>NV+;fuv$A6dD zFfiYYWr;HEA|<<1Vf31F%4BYk9q>N2Q$453?wR>CyjH|PQ5Xk%NL4zCA8d&gAchst ztRod$M|p$7FLzw@q25#A3vPjjVs4K#icK{;oRq&-0*{&m!mMt zh|6DYM?+m1S`wu0vQwGwj1EO2J76N7<sJn*mdUT_-`x#RInq9E7a z^jLcNEU+2y^3gp^zIcp@d)>Hp{wS)-a#3EGg;mR{(Y|gewymkh=9W5aY^uT1>OACH zQ;=`dw|6B+qMR~HZ@^qYZG>CSb+oESL5oj9dy~JGpFFkJJujMN;0J) zVDdE1Y8z4xWzwo%J|5{I0gSu@ALu@gzN=rM_wo_kJl~1yr+@d+T6iD4YiBdGQPLN_ z7STH`@Qf@;$a8&cNkrR*W?KCty%*@r{|J0Zg&iddA);6Tu34?)%y53=@d6!QZ(0Pq zUPG&Yxue;v>+M6p2o937rY2wtr%ZulvBv05WBvUEh!!(J;B5 zd%|xP>##XRffychz?Y&+Wx;=rWCsj1Dg{2_&15rb*#4(K*aGT+PQdLji-TOXagxc! zabncOh$d5sH>3)$<%^%AD<(Yp2 Ys`Lns?+??S$N&HU07*qoM6N<$f>j|v?*IS* delta 2408 zcmV-u377Wy5y}&gdw&TzNkl~;$f3Scx&Rb$#?%- zf-?#rN+#}(RY=~1h=n!e<$ur$JYQ^#3dFamW*kj6VV&6@YA@ak`b;O_*H}beZ$gBg z-7{f!JOG_Y@S-S416QCLg?beVbSeakg(E3yS$&<+4;ON6$kxclbV9H8${-ak<=fD| zC=It3CgaTPS$`<;lR@jnYftd;9_xq>M7~mtSt8GR4WBy_Bl1MFh!2}L4^|-$GA{eY z$Kb{Tu*xM{+hW3Sx6Fxqw>xYhxKoyZZ_Ii~`P?_VV}fygz5_$` z1-Q8&8E11N(Lz`db2)En{be|o8jd2YbwIM1x_4wnz7p+f?MGdlviVhu?1 z^~NTX7DtkeSV;o-N-x9i*dTP1`v)8$SQjEks3+$aiZvww`bUIJ+;@lo{-q)b!wqxs zXvG{RbAJkcy*Li1G9$3fqGKq(SDl5vVh00$GRuNPNugM+_r*?|4u_nf*q;!Lz3~Q| zOtav4iW%FZ{IO6jfR@MZo2ZRXL}>LDOYOdrSKlUE&`*H-2?HZ*itu!8DITqwhu(S7 z=pnVI=fTokCVL9ronc~Vrd|wAdx_C zm5E>Njx*w_E0)Rpsw;*8?_ZqGWZu6x12@W&J^}wO$BLf0F*u)V$JuNvDM=tYqV=Tq zS}az+2bXhL`pKO!Z5yfu{78dH@ayjA5cCn?^M$dPZ8pGa&|!@|aGdtZnJ*33V3yt= z&VL{xI%@z!d!<4E6_@?1l*5Xgt}UkoKm`&m5e_z)18^bFirWiQkZLlZw73`p0|O9y zd7?APIED5WyB;F)jNX}FR0Nx!k_li#m=d`n4%8gh;6(9FD?<8byj;?~DMHVH(>|xI z7Gn-$UM%qzA}b{sUlXv2HK&4WFl&*SoPWgJp?9su5QhF%iw5h0eUT&ZfS%(q#hj)v z5bY~^x;HL_$(({;D^0}m$bfNhgG@99oT{DHJU}F1f)ERZC<^dlz&D#z*hp9?lW^eA zc7HlW1C$n%k7&I?ENrL8Ci8x|ix^EW5#SACN+0{2(%u*qfJ+5&IG%3)q}4tOZhxmO z080!CG={4_0bd^~M~R3HKeqczIhWl|kBZA$PqE!BGV%RA4hv4FM&V$B8FT#=sMae8 zfDy;iOpM?T5%3m^AKIgII7ckGJHs;G=M%wc%~$E9s8I^gXpk|PuhL1dMCk<^`wK*P zvQaGIp;XL4u8<8ShjrgAU$6f8rhm(UM>S~}tV+eh#mUGGR3bqxMv=w`Ufd6mKoCLRlMd=Dh>++pW_iD0e=Y!XkjMfzcDga%v8YAn-w z!@%_zb~F2kMz0sf<9VYCf8SPvSFKeT-CT+1&E+^;l8lOIBUa7NKy}d^6n`qb2@_hz zUMGXodedx^y;yLi*fE>5aF)&&o8yf*k!?dSF{ev&qH!_DhW&BDs8tK0V0(nF~LD--|4p8748IlT5W7l95ZwM**QU z-J1gop9O;_7Y?HiUE5Y-UVn-O7JoVRIm1Z626U1M`6pu2JBW@b1C??<=?S*h35}@aplZ@w63T?ab_Z1=?(%Ei~J-zR+r^q z-pk}$hQnJ33GCnZT|1aj*81J7?YIw1u0dIaD z!SJI&M1<;bbjuR-9)I0JK-)i@_u!{G8*#XG8UEZ<&VcJRG8|}az=eaGP&+RXaYV>8 z^M(L1@;`t}S?!|eLpE7HdJi;X?58JqJN6p=eJ3z4+lj1% zNR-cxMO~2-H3be-lBu_lOuZaO7~&#=kP<^?{|E5z_BLb1{C`xKNf|0+Jj8LnfRg1t zLNotOD<%tOLzq}FVhvQk>)Epw{~G-Pum3TMzYSeuH1K5L0!|%jLr2SMY+GB4mNivq zTelSZ+t%Pp_jX)9+R9{3!6`FKT}jYN1n*RA4+8AoFr#V6xMP6w^{E{z@zb*b{PX3r zad4`Gzuq{32Y-ECxYu(Kch2p_jnf^|f*;@UM=Z*Xg+?O$_jH5klM+mf%qaC9DG3iC z)W+f=5!~qG0Vea`3%+B`0z`#qV3l}5$z_ksXdK%V(uR$;P&{0e0(&qqov#<+{^cXT z8@zMfVw7Z9q4S}8qKfefEtmEA5=8n+278IH9xuzr(0_&sB!=rqJ0{^oM-y(J-Sb)6 z4{WZ(+NxY6MFt|6*!g;5z0`iI$vmJt!DlrPt&qN;*8F5uK7QP=klBn~+wC7ZK@v|fAEd+(}K3+aSR zwQMX)?SnL>bSz9H7%_^xrif_r3;lWQ2J+=IV&b#L=vX##J;ta9__Ex0&8Q1z@cL diff --git a/files/opencs/raster/door.png b/files/opencs/raster/door.png index 36ffca6d68c296cd5f33dfe9d6293c37a9de9fff..aa48858efa1e5862461f899752a2c0d91b65a2c8 100644 GIT binary patch delta 1522 zcmVh*`X>N0%ywp4izt^vAEDqqS3uWA0DB{j+R)T-P&aLSbZXfN! zjmaqHdj$B*s()u$x309Ahz$i0oSm1q4#gR`UxMG6&0ulJhutX)%0VML28<@mc)eG^ z@-`Te5wr;%9IU?~M8D!pZ)nK?mOK7Z4XTIF_^EbdL=SB`XGl9Ku#rqLzr7 z0s=P8y??jH+9fzmJK4Tb<*&lemwC(=?dWXNO7K%fD~@N)a2b^MWD7{SbdRX_Wc|vJ z2PM|udbY2Jll5=(+L3l@Fq^kvzF@)0yct1@s%9H%I#BfMMXLO>xjc>*c+8Z9nmw-v zUntqIyTgE8F@pp@kuxLCt3=rjP{Mt3yh{q2BY#Z5v7#VN`>O-D5u9u%_^zm4g3o46 zjR~N5ttQ;zyj^mk5jfdC%HSgry#$}h7|~&Gz=48SFH*w2zb}UAoDGKy_O+|FS>*(u zW3~@RI1Gn534W~0h*%>6@=O51-`g9-!K_UZLHArPoT}a#(qW|2j)5ePN=87^t$QMS z27mHiP9*rd6A>oBilkFZONJc|B_D^PPls-=4h5EcdAC+NIhO|6HVraPHM$&Xs?_*j&~<)z9$;NO2b zjP0eie_h3z4zM*U68!3DpyA4C;Er}0uy-`ERyo1HxY38Mh)JFU876?>SBCxAn`R-x zvVF6jcREx^3o4}eRwUWUckno{D~2y`4q=h5wR)d--0feRwVdJ z#fyog347RS1U?njqU=#&z^lf-m=;q}4MJvx{3vFdOeFX+d)165j2Mp_Wmit{$%qDh zu2%Fj5d^2dgQf-r5PXrnXvX6PX@9X)6K*5htMEM`HMX`XnG3BFd?Ktypb-ISr&c8R zg#qWw;*C_LD}yZyaVWvkF8*iQRYRtF)v5zmwY>@_M|}Dw`7NLaB(2t& zjOp**{||V@-3%|+fB>6T@wAgYD%Py8E*Y}EYCmg1#|AA3vldVrf`%sP7+ag3)_M{B Y0nNHJ%Amm=Y5)KL07*qoM6N<$f^E3(g8%>k delta 1611 zcmV-R2DJIx46_Z8dw&KZNkl|Rc-r7L=Ih;te1Fm*K8;G^X2dQ$2-yT# z?cd{{Qw6TmYTt=S;-l7p>E+2L3G3Y+eAMU1m0lk%_js|M^Wxkg2c}aNG`Pfs^8eVMl`EY+Gp@3f-4kMS8FjVKjdVf$+;qG`87kd2Y zua?jewc$e6i|d1aTqP1Gh(yq$d*L(dcAbk|33#o-S|;LU!@t3JqPsbC!Lt&Ub=e9q?g| zY-kNxXn#9AxRj+?2@7xXKew@o~eeWgvPH^sgwo$@#gM^EnPR!Mq5j1P_sukdb zyFM6D_WVqjUm;NnILpr9)Ae?o?{H!!Wg-Gq>VFAvyz=gI$SimHh=lKd)Bd{W1=$Op zv+Pp@K3QkSYC9!lwGjbR2?Xkh0LLpQ-04m)PIq~?S4|E01(JQD&W4Fv8_ph*F_|>N zUkZU*mmz;0zrR_J4ey z{>Xf@Q;FA|p7W{|{63>}ZO2lx4U1_jy#=f|95tacOv6aT>Ro!cMUDC`NJv6{IU_3r zcdXfgqg17UFVtHw5H%7BBaYXb(eKy7DQMIuVM5a9ms%uc+K;AX%r(i%RpW%)uX6^U zuOrZ~fk+rIUu#0Ij|k{1)Dwu?^?&)rv|U*>2Is?43iwgFetjX4NQmI?9&Z&Kr4Wb_ zfm2O3MfSo~Q``e$N%I8XuOu2Cg7`0eq&~fLuUO zNbq;JO9M$;uHJ$u5m;!jDzfuQ<-@}1R&3gfflnnwbo=$l1qDneMRYn#B!3XG>hkk6 zOdPL#Qu(ly0zMHJ(B;!1OC%=aB03xuuxrcID-gD7^T%kCIotW9j;5?{?D=k;Gx%6k zj}DJcQDGt`piM4^t*R6P7HyuNQSAHiCOcXw;kHxGODX3O(L~kg<`U@NF#+{XJ?f}x z=>=RPQ%O1u2K5S=R;diu%6}3Fgopq?quBRCwx4dX<9$xLrmdtq(O^+RhWC8u@UiDC zJ9p0DqY)i4wh{^O19B`TVu3(-7TAtC0-B|j;^);=(trsXv~dC%jS3iv=y4>h!%&F2 z4rnppuR@=%620C^8DyqtZuu)kx2O(Bzo)vo${RhGC1icE4k}LoK002ov JPDHLkV1lHH7Y+ab diff --git a/files/opencs/raster/leveled-creature.png b/files/opencs/raster/leveled-creature.png index 4aa2c56cd7bfc3407f8aa7a56830089ccc022461..ad4a7c6f837a9946e420ad59b519bb24de3eb2ff 100644 GIT binary patch delta 2049 zcmV+c2>$n^5#|t(dw&PjNklwb9kVdL*T=RMDP&hveF0P?VK=<_gm`xt6hzu<<5rC za#Pg18ur@eC1UZe=V5#&;8pJOg|XfQKAgLN4}LO+_pYDAZ?Aq2^H+xP(~CXulp7vL zy*Ax;B>ratjS=tdcPI!0sgiPyXSGRK$gvBGrV3e{C+~=d$CKGf-hDf4RD*fj{iR4~Jjex_Hih9Z)>r`c5`)mfGJlQKR=(4Ub_~#$p z#I=hjaDREY6}^cNs$CZJH$`F8X$8=DJdXPMdW6Gafr!m!gT-Qj(P$LFH5v`nYBl6? zIiv>3vE=xdv5yxsJ-VH1Jl%{A*E-<`q7cfU`kK7qH#yYZvZR!pC0ghr(l zz*DJ|0PgX4V6|GoYGebeR4Pz;Ad|@;l}aIzNPi#_iEvOX{yY|N{PC4Ub$XUMVulXa zeW6a|v2bI21N_a?O-O~^0$4*s1Cq%ksw74XCgf zKwc0|{XFoZq9PR2dh0?j9?W0CyO&3B^U^To!x-Tl!=XxB+GEiT5I>k0!L7+&ymq`1tuY^(BW^O68g_#k zI;C7VIfEAz6d*r8AAYA5orx$W`;TC>vkr-n6NAlBO!XXs%cNQ1e%)m=Xx7ftKd%g? z1n`ND8bn=Yq0Rz2dF?9mp2^gG;8lvRTw{u`>cq$Oz>N^ zPc&-vH?dd@(Vzz-U2$}_Byn@{BwnY}_caDFbFvYMcuXMH*3yi6w-HjYNC4lvcYiO$ zqGAfDlO*|8@Uuxj+(y;vwo#mMFFAUi>&(t~*{xK6JRUXMwD=bfK)QEd3(GDM}@qPR=C6C8EVd zwJSYKWy+SF!IM5S%GL7wLKkHBB!8crR!44FP`Gr_0+B%}t?X9IHe3M#i^v1y{y*^^ zRSuKRYt?@mcA9X=V?n^Gg+s6W)T)+mM6y7D!+|5zV>8aQ*7-Ryf1gc4E|cBnu%QSR zNC-hgy)G^(5mpH=?tA*4=M8@*B9AkBIF0HRK6!V<0gI;WtxZ8x?XiuYYJWSl)D{mc zIxM=ykjwJ4_izvvo$8B>7YOvrOz?2rQb~lwV>K9*$q1lCg0GnjC@d)Wh{2pj)%#}- z`!E=HvjV@{M4&F{oVzj6`|r6;Zk-uOVxlVs3JK2jzf-P%Q6`sv!|BJN^E_~FKL+L! z6c!c=oxqQa#`1>`jhzKa5MF293#mfOlrl(DH)gv z>;%sJ&ji?noB`|!Qqg78DwY_$JH*bH&u>zIKTx8T)CVeVha9F=zg4$NH#||v|C8%1 zHxHieWY3&D6Fy8JlLLHJ$x83mR_Jj&VneN+#EeuMT(2i_GrBw3NpeS8<>GuLsAj)aya5y$n?^)oi zQJt5`Xlp#{tuza=!DCJ%%1s7Aq20T8vl3r!=dW*T!X+*PD}TYV6M@B?*cJyJru0}x z46n9D5Vq@KRF?_htN?p}jG6wg36R;QS$^*SXHolA?q-yhO%8(!4w{mp!u$>Ab6WB} zT!xn>K3WL7}&?`?##~a&OX^)*ar)X zd3ud8VDm5-f(Z~1et>c8`cc1=l1A8x8as-U_*KPmqE@2qk6Lcj)>VI0RVC+FDSzL_2s^CJMNaF@QjZd^ z^xDTO^X%g#E?YdH$fE{9Nc}pDZv{MGk*~K!^Kou>D}Ma_ow#!RIlOza4;K%1;$TA= z@+{K*pkj8;MdE)Z5OvwE9BQh-&t4hAnVrpOFUiL`uYIzm$oJ1f&6T)xqzlKkR>3Wc zpZs44l(?1qKYu^74+k2`;j@}2f{NVCK$LdDZ#CcOE%W32cRLaD*ucLflbDqOdMNs& znk5$C#rWBc1up#b^lrp_j>+Wr_`cX-xi`|c3B6Sz_$}h_oCMZ-lo*Lh2<-7 z2A&VxVzGcq1EbLhtyYV)v@|C1DP{O~RbI!`vwy`tv=@3%P36tEN)wcsK_-&IW--!T zix1v9f?u9Lj&lb(aC%o08p=azR2(gXSC)iPUKBvU=Rwf#f!%I@9Qkx`7CIBi%*;f3 zdOC?OjCYRo;Kl7t7~a)_Gea%dQxiehDo%MM<6w%PO zi)&t65y94`O}KsgHnz35;nJ}lHB&#JXnzJfHe+yL7xr)OLey(VZf>p$&e1c0b^`zO zR~PX6_eb#V_jcg*eI0m-$ak;JgHII3A1l&rHeU71#!tc)0|I6Nc_!h3D4HIz$Vwvx z*wa~yZLN*CaJ(NUXo23%Wq7%NGa70)sKnY^TTmDAz@XD&_3G6scvfZx-aEY)zkj*> z0^U5h4I?`maJ;h`dmGoH$tS~Y)Wzqt;)HrhP@^m=MNtsU_afkR!RxXk-{XM8W>M2# zAN8ZLt_Gz+KWvf-85tQ^xpF0zELnm)*@R0+yK(+-*9`EkQZGtnEo=te=)8LYk-1L7 znlg~#u*#DKM?DXVNubCzShZ>umVYi?idCtp$j#2aRqT+bdZKyQTVJe}_PKJO8hN3p zg<{a%RJ&k$PjcimI+D#o(Ca((dcA5iT;DZo)~G7y!R^KobIMZ*m<0GJJ3IRtuR+%9 z%rhH5E|84~$p&~u0ZyatV*-C{$tnRh2ewe!Hec?kDS^{$`t5WQ^w*U{DSz1Uh>&VH zxukXtiH`c69T3x7kV+9xtl=^V6Fp@k7~t4jAzb9dRp3L1|tI3wubE3 z8d5j|zn(#$&|!W1RDUCW@_*_cT&Dhhska`x>xw}yL9f&OgT`kx9x?Efz=CtSwZPJx|*?$->amj!2$;O8U zZLXS124{Esy0oiX@>k%j0q%qZiG>Rn!eY>$4M}=DQ|v-W)W9KVW3vd%byOlz?VvGE z0{c77UvQn1Yn}|wk*l>Q7v#=ZuwVf^Cf(GQpbfPi5jH_LHt&guA0W{kqPkD9x;YD+ z0Upx@mjL(MWYiQ=e}AtHKsJ1-0Vc6%(IN<$X=sZ$(BP*7i=e%05pAExqUXpb=K`N)LS67+wfUB%p}0qdo2(&U+#uXU`Mp#Dbm& z9Q6<#IxE~VM2em@z!~6qb$a^Le@%dtKg@eO*PDsZ^}Xc9?4q&BZXj_AI_Pq9)TlEE zm^&ar%bM3RpSg0droNC!*xKkLIl~1X^o0FYA$zH%&Sg~RS z8&UL0Bxdb~+;$0L;iDDre4GKcRsx%`k?_KlnX3fKn)rx@lb#!AGO8ibnC~NJ76D5A zLk4CdJQCL&5fPa6VUZji5x%p0`Eqr8rsx0m)Fq&oVmbU_LEG$y6kVL6W7Wq=h#ygk q_46%A&qe5+4{4pd$=?8Tz55@NYw_ktWMjYp0000e)Lu4Zl9wqdTDmADB8rN-_> z&=&|iNgaCu&mM#>o<#^f>OsYWh+t?ENhoNF@U;C@p%{McS1pqAT zdM+g?>Jo&a;B*!}9#0gxYr{oRyt@sBM(uVR8jS{A`Te6)QGblCCBO{tbUNyw0cy1x zWHK2zWZ5G1061Q+*QaDQJp#V46*F80Wq<7TX_Y744$8)(H zI8RPK7>2Qv;D#!o#mD0@Ae?2{{wlcc09t%F96~mm1@#}zyP_zYq$8jGZs`=@cq)|w zK@e)&TU#5e;!7*A2;a5YUd_V)44}ok-7X}PNmTZVnSc1N0dPE#NPxrP$eK}d{2M=d z0LLHh?_tkwf2M)|sDKu4wOW91wc(y<;okyi@n*9L@pyb7dA*M`@p%9oN0)|Uo;P%; zkOsBjHx^lzKi7p%D{$s^zoDB-xm*VI>eN$YndndH5M8bhb#Es=REPrv w0)dw!jwkE?2R@yG9jo;<91gF1sE}6R3taM#(lq2t-T(jq07*qoM6N<$f>S624FCWD delta 566 zcmV-60?GZK1*Zj&e18^6L_t(oN5$98N&-<72XG&uH>h5qcABO3p`)o~m^wN^ZCo3O z*|M!mA-B46rK?;hh=PWpxDi1}kO5n?5F&^K(bZ|LU`#h{X6}5nnB6$P|D1d7xsDD1 zbXr|!9#7OxQC-Sr>$+X8C~`H!9d`R2!!WZ}s|EFX9nQVp8Gjchs!4za-fp*HI2=N+ z*MnRx2d2HfuId4n;k8-~(&;qp8jb1(ScPXY8E`lpGqcI0-VzAmI|jp@YE38>S0#WH zT=4)>aYX}=;EDwx#T5yFR>drnW$aDSQaZ?Tu?8~G39<1EWUsZ;_w5SU8EiFyFX3xxvseZJ3t-yanF*8KY< zRRG8H`8-&Ujy|~cHk06zD!|7Fg8?9%Yqqf*Tyy|F-tYGzo6UmD>3nBGp>@(XU;IvR z32;1>N`cL4Wj8lA*5u-X6&GRQU@Lv_+FN zXxO({BpoWGL3Q{S%LT(swZi8Wa2_AORjXAf7K;!H20yvaC!#}zxB}sD_yzrgp(yHu zo9)Dh3NLX0nx1;MAa*k@H7+qQF!XYv000IfNklK+1xDmAH;Hx)J~q5sh+2R~E&2h>$`!@=#Hu-y4Iq&l}jQFc4zX0$?P zN()GY+M!tyfFhTQWfX!BbWMhr<=+8^Ee%#UD`3N_Yml+18DhiAfEUE4XDk4JHJnf1dnKxb~i4ujIeN!V8rVg3(%{L&%Z5c@YZ~M+EL^P9%4*{q}V(z z{i_$90FgjJFLl&`7*jo)kpL}ec(66E68bva@U+tn=WCvNYwm$BiQfr2(#9b8x@DIE zmzb&8&|*jo-wR>^dEIXTT0-A{n7%X{dfNYiKOc=iQ|+@!@GnzOvZJP=J#dxGPKW6; zAuaX-2zVk&%r`{)CBPoySZmZ;=+3J{9Q<-)|0MXPjH{^b%-UtOT;xXbGcc1WV+bx4 z8b>gma)n<;gvL!NCr0mHe9ghz&c2ugkBiI#6>gvuGQ$|EIZC@ly_k!CTr5!2GAuIJ zmG77zuofp1bEhp8a8Tzj&rPml1=wODYJ}9g&MBr2u?`nj@-4Pk)!a}pqb*0B&w+OScpA;zsIZKIe#$dqnrf&DvrIrzrR>mb73jv9iS zRIAvgllQ)F>G>qUthePFb)oeA);I9*rVGv;?T6a($56822f(EyePCC|1h}4v2T!+0 z=n4Si;e8+4xKj#X>;4HYQ;xJ!ZFae&P)C@v_oLL-w6ymJaAPABSqsH}H zK$Ipv2Yg zbM;T)M#})4s_x}~;2BBfVAMrWUNqa^ObvuH~L>fveR5LNgGGOg>L=dFlT+WyC-iO$(kFgpf zsOIDS(A?O^&3Z}JEf5Q3-Z@9`s7ZQ306W`i+UkZzL8O6Y)~#Sx!B*d1XJ`XBxawM eiN9dad;bC>OqY0Jk>APy0000j4ekq&B!2{FK}|sb0I`n?{9y$E0004VQb$4nuFf3k0000WV@Og>004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv00000008+zyMF)x z010qNS#tmY4f_B94f_ELcQu;;00h2CL_t(o!@ZVWY!p=#$A5qK&g{-icem~KgO(O( z!Nev?u|-Iz27M6UG*KdI@DYugh}f1y4Vu(oVqz%Z3t;sDUi8V>XrKXO6oNtdDBUPQ z1u61nKbD4VyJdHFX08w0#&y}YyXE5~lik^K&-wq(x%bSDpg`;1;M*;wSna0lRnP8a zywLb;(+XLa09nXl&!ftaSf&obQ44QZykLMgzT$Y% zkQ1-+T!z1Oy6*&lUT8q-x|i~-J0U%X4%`jP*@4q-Gzc(q`6Az^W6G+j?px2YTx%3u zY2MDroB&R@(IDYX1r@-WY`>-x0;pTY7GO)3I|>{UaDN8aGbaE6iu3x9C5Q6eYX@#PKB+e%0Y&MS#7lbndfXqpoM1c8`aj9*h!FK97HywDUSgFq0+xKb$`+uX=mlE0OLMZBpi+dOwl)Y5=CQ4 zz5vRjLI?%{RA%LhYBfWg4lsOy`y$;e>4Zm*bkVXE4!aP!^cw=wV6&O$vb<+EdIv21 z@iU&@2A6=Jj_xDsy+sK-iRFqDyTg2J*ldz<{5s$P2_O#G2A(yKof|LHK2_4*Mn=jP z5Pv?^!%H3T1waSX&9CE^*xytI0SoX==1NKs74%&hVr2(7w`{@9fccc^2!9z+1JnZZ zfO5b}A|1ng^5vjeGGqA*&DM!wSye{*4`eD&B~aplVdzcKK;ZFQq1xIe*^?Lx*IBx* zTdte*L(x4{8Jh4_M{|bmVf?4X~1~xk&xXIDn{Es;Hystf>zk_C!)eQ zQEin(!xh80gZ!hxMRR|UGl;YJgs9gYEKf~1kpkz`A5g(ZdeDaPN{IFcg`R3qYrGE;C zN5@TH{KZRG2WOhaX?=@I%N|=4zVQQiGUbBfrLWh^(*U0ygKGiMB=|J&Nf;UreSUUm z>=gw@3O>lrso;PCM{b#dTo&* zlb=xmn`V7hPnl`fS671>HBLWuJ^)4XR^QFk>fRPntyJr_raI> z>gR1X9JE2rbfw^hJ1(3B(K7?Uy1Oc#0kJ=a_;dF}JOkpJ4Dq%1R6GM>j}6aE=l>U8 z+sJ$y_4H8y001R)MObuXVRU6WV{&C-bY%cCFflVNFf%PPF;p=yIxsdmH8v|SGCD9Y z42|5^0000bbVXQnWMOn=I#q3NWNBu305UK!Gc7PPEi*AxF)%tXHaaynD=;!TFfe`4 zWNQEb02y>eSaefwW^{L9a%BK_cXuvnZfkR6VQ^(GZ*pgw?mQX*0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000NhNkl#u>-THd>|<6UrE3m6MT~lrbUW z8fSuUCUv1s zw{1SdbT#SqU)O21=K@+S`nGN75f23dxXjs1QZOF8O)TajKQvyQjavgm zZMxn5K8%JZ;PDKhpkN4A>uH!7A2#OH;&MX+pYw^}e;0{RCXw`y75T8BaRumgm43VZ z2po<<_llMZrZ;frk>n zZPGCnH)CTSzvFd3jRN-?B*h0{(61%nT|As&E51Re~N@Wk!iWXSpnfPP05<9}f zu}~<)MD}xx3HyM_ka^?$M=t|s58%!>yD{+DX52Xb683C)3NA-BW@%i|(scyB19JIU zNTuI_qE0{|T?vmU0l7lqxnF8>;|gf3%JXbnzZ7-Fv*C_cqiU`d?Hd;3TG#XF|K~;& zCQ8wqB0yte5OR!K#L{jkWDO9D4?`$CMb^8Zr5U#+lG50RN#6-!|a``GdblZJv2tc(FkMFC)NQjR2Imd~n8$M14BLSxbyA%80`5A0ySmG&T=8J>{0Y~uE&r2)?)R-G*nuq@wR)DX*d&2 zD7DPM{qSsB04e3Z6&m^mabX)mL!U!Lc;kRb=sp=1wp>1@fZREW?;hFFg1xV`V&IGI z_X_Smhd1z%bMQ-@Yw*gd0?dnacyv8cV zQ7NeKrgyAbl0P_H?GM5)?p+O^Qx87p*(TKa(r|ibE%F^SZ~HJjRVIL59(i!e$B=6r zX|oj9YYO7=4^r*-N6x`d?`lG3tdK7_ABnoAC>eiS=Y_`{IRfsG2%wckPuPaXY($)0 z6}A~@atPoep#59xc-uL6W2pmfs{|#cV7}Vxiyip*WgmPQCb;Mz-gYi>4sI6{0n*6t zrtAQ>AI8ji^XG@jyO%!Ku)6O#-2@!aQ2-iajLC)O!)B^=Hck3d>FKe zcNOxYA0<>-`(%WSNC7#5<}_V6oVrk0)zQ5M6_v~Vi95xd+OjZXfZg4UZ{DgO6*&jr zzkV(`6(vy0S0XH|8__e@+$R6W@1JxLa!u&xwmIqrQ#8lcaqz_oupQ0!a?aWQPHPb| z6LO$a*OM9G01uCd*oYJ=9d5b&;kEjoljA$Uo2)zghIA3I-2!HMzVH_Ix?1k{{dat VQyCYsUSt3O002ovPDHLkV1mx^^wiF4z3K4dw&I;Nklrc~H9LD(*%o5{U_h!kKWt&SR2#R8%+? z522A&;K+gfIDc2FLI9Jevnao z5lKb!L*Ri9*tzF32-v`h2xXEK2#=Rya1`hnoQA8rf$Y3e_%V3Oz@Ugwdz`ST2ss4o z>&qUPo z3t()D2pFHXy}9Roe|UGd4G@WD~U5Ft8{R6r;ku)SrcMa0FxQoMZt}e z({Rf27JqWEIp^lcXTxP}z>QYmI$77qx~c(0S9GBHhZ30!kNgD%Fc`t2qO&rLl87nz z6aD*YH|KnA@J`i)&5_TA zUups_lEvMeGO@m{1#-NSHesTy3HqEG^#59do=xY` zwXql-F~!g&Nziw&47yAS9&A2=#%(9insN%wNd>6ibQrSWY?OPZLlBh@SDNM1(n0_? zBwFzN@Lf}%8{3VTI;ey(;ToR*R*B)ba(|5caRY{8CG=-*WB61p1`BWC$+0RET)X28 z>N&?CXB>gd{~&Jq=b$b)7mBD{G{okhHY^h-IYQ9b(H55%3jzKCT&eM-76YW^UgWDS z-~+Lj@rW-mMc%XH61umaNBfpyXf}&YIajjtX5iI60#tb(K)J_$Tz21wi*9>x)_)}# zr+9@}?ah_WPJ@Mju*j{7@q$M5jQ}G@@6AL$8&28Y79oZv?9Z8kvjr|*nTQiV{tmB@ ztqQ9Ge2D|kM2*mqS#P%eQ^NB(qy`pqASgIm(3@F@b~4xdbL;Ub;iB(%AlEMo>sX7_ zfG4@n)udOT^Ns;Mq!`UP|5)28_~vboRAtu_~)>XQK%x_@Q=n^R%+ zKHx(SdVDKRifWP8rXgbup6-?m*R_ntcHIZ4FH?5W)&=NqZn=Ou?s3z2wKm}vgS)u; z=pDKdnMKf9k?O+ee7oWCzNuIp7^z+iZu9>FdQen6%P-Pc5S|AqJ!@vR&x@Rl+TFhC z@TBpKYZy`SAG(m*EWmt_n?5Itzt*3p3}wWQ#{HBrl^m3gBvu;uA!$=AKmMqjFHh-A fWASYPo4@lP1|UM4=tf9X00000NkvXXu0mjf%O%u+ delta 1773 zcmVauk_J%ZmSs5? z*aciz(B+6AA}W`lBF4(02~iHADi99QfI;Mnpj3(|5d;OKfCezAfGC0k!s1b@rqy&l zeU}an1d+o@|9EEinR(ym`+2^<<9XhBz`VH(x#9d2N2B>Y)_*$h^jT@Y6F-+V)bGqm zT>YYt#hYZf&tt!09*(+i_5NP~OeJ<^dWNEhR(8%RJCQD7E6fQ|m>|~G#7wGC=@^I} z8e7QBW&<-T2ON~%`97OI=j*DQM6Gh9B_o{b{h@eDjY%r+!aXnw3kTP%UkpIKu%(@I zZDi_kKJ&1nIe%|2HCeH^N(|Vt?--`GirU$T&p8LYLUyuBZpEJMAw+KpKyGc0Ye1B+ z-s}^4Rv{P@SQ)%S2*Vxfy5L+Vq@3vBV6>oOydX#u2)m8aKk+e1cW4~2CqzH58VxejQ&0d0NIatqD~^P)?T zeeoFyrv`{D=)fgt7bbRYr>ApcN`Ma*EO^sMY;`v}>kRql2e^3kKV0jF!3Qw>59l9( zjyupQw0|J=XcB;`1vk_n84W+Nv*Z@O@h8wWGQX={YbuZ_0W4&St7`G$`XSo7K_!Sj zd;;Br!tRCn>2@ejc&%NOvsal>uxjc^QqgSQ`_$IT3B=JV}eB@5dLM8FuDeNm9 z8h-`YS@8(>*m86&ol1Z1!XyAE&p=h~(aSV$${UTjs-TsBMO4zYI-4@H?UZiHrJ}t5 zMGh2KsyO7ANxHT#$0bo*Sf0!&yBIPJg4nS@L6jnzsE{1|S0`g`>vjK?03u5}v#-1p zXpqHmH@6v;>N(GkU*o5WP9CS#GqUw0b$^OP3XC>#aPeBwwR||Jvz`-@NG`gj(jJ;a zXG}ir5!qZ294NKfC4dAI|H&#s-<6^?UBjZK))P+42@Xi)?(rqAdl}yFEe|^$Fw*mw z=VjMM#h)B+HgVE*O3@W74_Xt0%K1`cWHdi+0&=p%mS9}3Yfd^>XkU?uiCV!W< zrBdUYNSWeG619Bs(o&*h=`!K+G6BHUMqYSg4f6)}9bGL{OrX!bAm z$5Z=L7MaKj$A@78fUS#n%_(s>gMUFq^tarjzqoT$d?2KRzQ7`S{POAYJ4)xqd^$Gd z((0ehrL~8sQ>IYmwC{y@sm*SVS$;u**$$3~!pSz;MuO%#JbtT(jn|lKaALqeORHPL`(Dv2Y)Oa+~N;A z?c(OTBV4Z<RX1m?Kpw20QuIx4%+MdxZ z44KVql^aj@6d-#PaDo zq0p}vtg-idnynW=yI&qB%kEJbS3j$S8!sOB(RviW*2YNJ@#&1t0<}ekmJWqq+JsRc z4x?dx-fM|_|K1F%KiZ+OR63#l$3ijXeZW{Gy%oLGU#Q{W8JF76cYm%Hw|-lUrjCVh zZ<@t@K>e`VE(1f$p$L6nl7)k&Toyap;a=8c)O9{yeD}gNc>Yc_Dz2ezGBl?f(F+KP zbK_dEFX8XY1(0>*inmYbaO1^eK3pS|n+*A{gip0U*`q0TYsjB|G<6D{?m{|afU$)Z z8{7CTFwo0LbSs%fEmB{{QFCpZ`ysIPt%@sOSbz&H&^H znmGWQE`M+h$mj5X!DR+SK3N&*7KFcRenDF1u)|PfrK!1wmR1X1CEvKpj$g!Mi z4j|WZsyKiW%PDpM%<|*MkN*c{u@4_UfN4-xLr?9vN?Wqa0c6YF-P}G$gonS~x^*i_ zmXjR<=#~SER@>a%TzM}~&l8Rg4j1h0>`=;ke02@UA%M+tN-8sw96)W$Ns0nmSWdJ9 zXk|H34xpvw1b-bsYs>LEfF73PbO609$LaujT8`lWdRva-fPt_a#Q~r;JE&FzRV<*g zos!~}6usc0I3+pRYx?x*|LyGTe$vx&cnE-kKQ1=*b5~avsKt7O6dzEk7G4>}#>CXL zG&ldRt*QBMWobz_N1)V(k&%&e%F4?A7v$&vH#0S*i&7&ns$*a$a!zJO#{Z*7ks>r{|ogsHkrN0RjJwjf|#H8qZ|4h)hjP>J0St?}8F2Egb*=2f$1v^&Q5X P00000NkvXXu0mjf+^gwo delta 469 zcmV;`0V@8>1jhuBe1En{L_t(oM`QT^|33q*v7&;4fTySDK{r>|3$89ME0FD@i{(B( zK6j2DJ^KIZ)vNy(ELia0-rjx}%n>wo0LbSs%kSU64|c%e!-xMD6&2kD${BzhK{E$n zvm6u(n>TO%pAa8^4=ArdGY8mYRR@q`In^9MuH{s5 z040`F>;RbMt5>i7f8f9Ya6X4+HT2YutF$G%96+|*(ZS)fzrX+6wQJY@U%!6+e_|~s zI|R@zx3{yiO-f9ZcX4(;VPj)+!P?pyrM$;i*N_|n*es`{G9$?W)V7?YD4>PqL_2_1 zmJ{UwT3Sxf0e`f%9IpfDVL46*(93eH4xp#y7!IJf)F93BFo;13B2`CL_5339{{QhY$ET6kp?928VjT2k`A zAV2@VxtST=9D!0B1_lPs$azwj{a|GU_f(6 zU~Lb$y1LE@4GsO~>*Mp^$k1>KrSVKwiwGD6b^3aGpiZO!Egb*=Vzf2XeRp5d00000 LNkvXXu0mjfS=8OE diff --git a/files/opencs/raster/random-item.png b/files/opencs/raster/random-item.png index 0b2571422cdf1f9e396129f80a800dabef387d88..7b8e68e60543867519ed7518d0061c8a21be3b60 100644 GIT binary patch delta 1594 zcmV-A2F3Zw526i_dw&KINklc2^rkbttJT4Abfl385<)_Ngb+x= z5)#8=2_T>#P(VZ~;BJvBt;L0cD6$q2M5z=gRZyxFMX0qbiW&mQCKgaD;B=mz@64PG zArO)aF21XioZs_q&wIX)0DNT0`FzzXfvdny8mJamM@Rakl7Ihdf+W`AA+jcarKmMH z(0xSi$!jq8ofg4EgQaz)mr{_E9fxsUHLAF+7Vc>fjLuFrtNOVGR` z0>U)Xk-4`I@!?%B{+k)a?DP{%k2d1X*gd>^-Hlhe8U(0BIx0&auZV!He!}L5_s-$p z*Ufl4eiQ!;Re#d(>9IB%o=0UyQ3*(73UB9OUGGIq43uJATa3}?g&6KD zz)YtmO!mI6`mi3}+kO_M7m^U{@ASut3!t*FD!}K{4@Z-&5E0Dz z;48D63kk5Fjn#YxrQ{P(&smm;u&4y&#ZrkQFF+}Hy?-;zV@|DbnDdp{&Z>Pmv!Ox4 zIfa}ziayNnvSTD*K(hQXc^=(>t9&|Qu{f6s=m+-Wi-(A~pa z5oTq8G@qZhbJyj<6if`(V``)w6T06p{-Ob6)ERwNkD;C_^mUv^SL-S4itw886g#Aw zBVt(r{(mZwdaJ^9^6&e3m>j-Koi?iZuA={O9-cq?5q+KK@TC0=dhTb_@W*$*!=pPV zabR!Ydxeajznln@0s_@;`FrBG&P)u{P_y1a&3y}oo)j+&?`%GShc`2E;$R2_j_ejw zB9;^&7IIoH<|I%NH{s3rBfRRbr|Nv3hPO3k;eT*?I0Dsj@OV6^m7Yk9^~bI2hrqxe zG-jZ!;TX#E;-Qf9JC<_CMFn_C`3;2npZdee4L89orVwhl^I076x`0v z4u7_`ws7Ryg%X}FXmjX~s6 z4_6#b3xz~1py6yb8=E$5!p<-+I&ucyRF#IC75h-06APi!=Fa&&VIV-Q6!tLvf`2!br=X!U8BrR^jKI-GZ&rE%6kL7bY&^AI zAJ8VlG~E1Aa}&AfYo2v%he5-oB?Z!OYinz4+_;fWI}3wi;b zVs6_&&t*)$ytgQv%=w+#W2h`jK}Eq{19;Q5gK%+n(8D*gS&PDN6egnPVgiB`&VM~j z8T108!o3E`sExh2ZuXoXKM;o9F)9Q2h7B7K8YrP_K0k5>el7niC}q4sBLPWqDlM_s zf$k!c4#&)SX>Ovv=1kfNoNe<3DyZ3C3VxL;!8V0JYb0QItWrz7-ITq~H<{v`c!QcV z@WLOWO~Na4b|J`j5dn!YO6};g+J7azeWAk@o{iJjoWP^Q({SGPG*Ez@bc^(2=L|`mw@`v=zQ_lC2FPS8Em!1 z;KXEptw=?Hp9o%_PEh%{pytwUdd|tH&2KnTbCPxvIf0j*iiDdJyVa-%WPcLJ^s3^o z@w~G@zfzZiGY*$~at9K3`rvHFcC+CpQq)9%eogDgka%>|cKP(v2f6e(f0SvK;LtZ=BL-0AuIz`%eZ`}wSSvQc;3-q@U~bR-5ZS7 zF-ea^Xy2K6Kx4F07kWEMJBfTbIEh@yvoTu5CNCx;XS)cwgxi;zphEGP7?a+*PT^4;2&94!;ho%oJr@xP2FjOtnYSgaUU^5kUlrGvY{hYPL sUWvmIlOc0XMoq-GsdlupHhE9@AL3)&a$Qp|g8%>k07*qoM6N<$f{UXW8UO$Q delta 1891 zcmV-p2b}n#4apCXdw&NwNkl@9t3Xn!<5TQV@Sp;NhQ4m>_0@RU4QCzXLr6a@OP0{b*IQg36d>zW%76Hg^t0q|f6%R!p9%Dp z^tvmB4|D-Cqt;WDWzYB84OhzflE^R(67~e)WJxrxUdq71#9$EU1N}O=v9=->z3pje zYuJZ`UF)Fr_+JMg;}2dupNa`XHJ*=F;q6ot#vfJSdjApJ8!W)YXeGu*P9W#-CMcx5 zE_>9|_t>3*5PzLALLa2~czYm^f&csCbC}-V#k=W$;LT(|UXY+Jcc#O~%XPwD_@V-! zZ}w0LQ&0f71DJO+KFNkL&$iOj-}&dxeBs|9=TU zF6Buy9-?0|lE1~(?hIVJl!>mEWTp%kniA2`d;piur6TP>FeGm5u}yl_pX~``!3J1!PEPdFx;!cFSkl@vo8lf6h%QPxm&ukN4x{(>_d&cH#NsHar{o5u?K= z@!;C`81BzSbLDPq&?!wyDX(R|AZ!NkS+z^wu74Q+5B(j7VI+q0%6Ngy|1f5r50aTb zM--Q0^iBy;U5rOVMR+(^$iVMj&BN`>xwzGvgZ9%2NQe!DtH9|A{Z3nfd=&t3F$qcC zSVeI(<8agCO$2-c?_S;|LG;1+b0u!{HYXuJeG?7ht(QuuogIW#0PEMvwZz+}J6n=4_OKi?6W#dNs}V-|#Aq{Pwbdu~ z!^=wzsZ`3q#bPmBU0op(i6E1TQS@Cj%RV(}wf(R9Vta;XhqGVyU@@TEf8DY&KkkJe%;Yy8Y-l6_1MCNNALTH}tk( zkuh`L7NIqb+&qTYFM1f|w&1keJ=~R+n&)M1w`#bQ_zeu)+1VLRPEMAzo0Xg4?Nxhl zwmcSzF@BJXIkha6oZt21sl9kPR)5bZe`W0YO1XK|u5@JKO!WaYRV7%#`_837rEs&r z`8+mLb6fDXle=(^1W-UWr_7E0fVIwF`h?mlo%1)7LvzAy&3X2raO~Nkvw}N1IwEX? zW?pzp*-ji!4~0auYJwFS;%*q~&ta5Pdo?%QLMBsNw%by3bJ{7K$6bZSvVS|YH^Zw6V-|!r9*;s%+Q!cT zY}Bg^13g)cz0$?9kaDxhR2RouYEI$N5xzKIv(GO0>B4QuPY!`X%rUY8*GQhwTkhG< zrc;5`Lq+(9w-W>tBNml5S z;WC?BZ8qHOaHU7LVRuv@j%ROK6udk$6d`^R@YxP2%r0&a`3HAIyFPR&cvcFoXvlk0ZJ5^5MOP4N1Ug}21 z;mmVxOL@*d9oA{w;D5q(v|LG6_W;R6966z8j*_2OjpcFZBxW+#R--0E(@vEy1gAAm z-Qf=}Ip4He=v?sSQS#MA#GGR)VXaEa8{15Fck-^aDE%%1Ww~2$>Ua!ljzyvB`|bE4 ze=D=qP8^9qX?7S&$PX22ug8eN6dc@uTyh;BCZCPp>diEqfL!A+MU?C3y@+Q2ldemp zgquaO(m`Ht`Fgn;Je30D8V`}dhdkbD7lT$UG-y>q16i*IFNMHB-HjTITEcxu$BaBJ dw!miAe*lrQqikNLH*f#|002ovPDHLkV1i|owQ>Le diff --git a/files/opencs/raster/repair.png b/files/opencs/raster/repair.png index 5e495d8fd72c88a04aab96c5eb72ad11fb5ad9e4..6cf1c0aacd2fbb94db16cdf30f0008d8c69e08db 100644 GIT binary patch delta 1036 zcmV+n1oQiV3fl;fB#|)~3K0MR3lRZ-WM7eyQz(A}*GWV{R9HvtS4mHsR}}S6$Ui9E zr`d!`3BfgXWtzlbX5(VO#x^b#%oOGsf}wzjC?F(2Kp==wh*2PdKm>sZNK8UvgCae- zU36Eesj9S_(|e!dDy3kX#1UO&@fQBR_uX^ubndkRfZ{sOwSu$bp9oxk1fukMx6Nu5 zX%>HrFsG)9l;mV#N=gzB?%#i%Znq1&%_jK0H7!lvv6#*BUh3Ps$tII9(Mh6jzBL+! zkxrt)APfl!B7shPe7uN@jTNzUVq#)Mbab?cii#3?yR%MPhYx=}J3GV4$q9~+ zk8yZ-i2eP2l$Mm>=;#Os2M6-^-rgQ|cXxlWv$KQk?QLvrZDDhB6B`>FSYKbq+S(dc zS68vJvV!I1Wh^Z%VR3O03kwUFo14ST%nYWdr!h4(g~`cDjE|4Qk)9647dLOZ8Gt|F zi+qV+lE)I94SI~t&(C9acJ?1b6B82{8ymyO$OwjqhcP%fi2nY5^!4?jr>6(q-Q9oa z>gqyAM+e&5+tJq6hSt_rG&eV+u&@weDisvLw{M$T=m7(tC*UE*o&*BCy1E*1adB@n z8qMj~8coONK|w*X2z5H0QKMG7Gcz)zH=YP^*aHFH*w_fIR{NTq-3ki}yY;T{{i_S8 z@Qf4|cTrK1OabToLp{&R%0lS9d#8WubHE-F7q(%zR%=u$mA`YreMru!d;Us}`KyZbwK+NVTsypS($7VE}pAYdreIZhy8^waKC2(MZ@t; zc(|Jj)Sp(1(CL1o3cnFB0&K`^HhxxoX$Ua$Z+^C(smDceSJOZ>gqt#@289GoG135HndnQct(R|XlO`Q{J_9~ zlw$_xA>#|2Td=maR^ILH?L~jX}-6WnTZUVq~AFlU1+*=JHYFGg1~A5@(=c>0BH|^tSZ8M^ zexwEB2`>;WE%s+|lEciTIK(BiHF1dZ^Yg)EvWZM4k#P_ao6QDV;gCuMXvKpu zF%h()fieES1UNh&dlB`T0)NFLkoT_te?cI zudlDgjdU{Ik?tku*tE;Qz=;-*TpP!%Pr&38O`k$Zi_3@E>=WbaIlM=qMBlNp5fdy9GV`$H~bFE-x=} zadCmOvoq}P?;|=Y3QJ2%I6ptf>FFtskB@P9c!-081MKbXVSi_52U}ZP*x1;>+S(dc zR#wFGi;IhxpP$F<>@23Ir!hG>iShAqjE;_Ccz76tgM;Yr??+cx7lML_jo12^9XZio-<>hOznVA_(O-%`~v9U3XjEo4Nfq?<^ z_4T2*w--G_kUL2U=QMP+VLLQUew;nJh9dFAoa~3!)%1=VDQjkphG}H|}n3 zZVn7+=#0UJhK6o{b$53Qu(q}~w6?aQxw#pQjg8Qkl_6B4`6QRi-#N(Ttv^^=T8bf5 zynLypJGv@;^G0;Ql0`;D2uWFXgS7Vruc)X%KtRCXvVZ5#5AE&jtc`>3h6{dr@j^>v zu2>#TNQh8`uZDl`3!a&o30oVRcQkM}fDI(RYC{JH2Q9tyfrp9j|Gwby@$nz2<6mxz zdXqUoFZS~+9335r!$ZhZeb+lDaM)N|>&@+%TM4ig6A}_oSy?Hp#n&-0F=2M#N=r*w z_I-2UcYodmq=t?{<%<2wN*JtVYT7BBKG1}J_h1CL5T)PuTCMgkwj|rmq}B9#SX)_b z+y(s33K)t}l)mMh;E?&6&+F^!k)ECoit(gJA>gD?T=5`s!hIex3|?DXi?p;f*xB0V zJ~#nNF0D?d`@~nk@*5|d0lcQB2Ib}DpuqX*3+y;M$)P`hq}obhOxdya`uVSH(hNaPHn*=M2snP)19Kmk$pruU#h7-rf$b zZGV=4VGZ*NHDxtZoijMA#+?@w6o9uZUq@C}7BVt2gc`RJpsyPL5L!Y!Ok5y8KOecd zxyZ@R7Dafmu+36aQ<0+6At@;diHV7bkBdWWY^>-olGZrOtqlu9XlN)j8V%I1ULiO* z7+jk%Om0K6*(qCzrEY3!LPJ9X>gwtQp?|8XD)3t6`QR>#ii)ng%qD_NjxET<1S#4D zG5-;w025@?YBlH!?1luCqb?>` P00000NkvXXu0mjf{DwyH diff --git a/files/opencs/raster/weapon.png b/files/opencs/raster/weapon.png index b68878a54abbadce500135ea0dd77e7e53168118..3d4b534661076843ba4db3fa81c056d44e108cb2 100644 GIT binary patch delta 892 zcmV-?1B3ji226mGcx(sEIm65g?=zpA60SIm~nZWDy!pzJJsH&^C zn(J|D)U2-?;f}5dFb>laY~dZa2Lj>K)6-zJTA@-d-)c~c!2F^P#-FRepy30?PV-L( zEeTvusfM;Y_rWJ7CSYuA3@Qj>t5%T@Z~Nt7d`wVtAGjy>oj_A#WB=&rs6X~VxY1~Y z-riow$$#dqT(8C8Wp^p?ILGaQW!RShGTyrgzOk_Zv$L}h46fJffy?1gbthem$*Tt~ zs{;$baojL6GUDAUJlvl)q6859+2G(hUGRt&5rW_D==dEDUQ%2<6wdYb=X*+EuW*7O z`XhnwDFK~UD+}jb+tT7G6bkP~3J)s)!P{C}$$tgs4cYC@&CS1fJf2}c@LdIn3JWnG z+~IHp9kufE^7VtjLkd7}GFBIIJ~uZPHF!_~2u^OfZ?S;y5P;y4ii$Ol#}m@IQlaox zDV4JQ);#1U{2y?C0yo;*8RVbs`)$bMJwzC~g8kO*MPy}%<;wSyJmZstM`E*dSB;<&=YZ3vchrGk4 zfJgJ68{u|#p?|&62$fu5CvZM5`JYL{gT=^)Hai(SPU31x@)1=~Ae#bA&36s>`Sl^@ zJ~iV(offj})V2FHC(wB_12x7(q;d`~Z-ld&0J$t*Df?4%QG+iZ?qS;AfQB1ND05OH zI%hornN(`;>gqy8dHH&kS%s;$x8ZnGi(8ka$U4bg3x9XcssIANQ(uqS*;yC^wAbfgy8Y?R+n3+3^dp>e%PE5SfVF`hRY19Km~ zC-$5GO@Gr*qrrQ7d(qzB4y)A)iCFZRv#?hB4ku>fFzO4YILZONUS11(z{lKFN zAn;O}c5UaJ4R}NW1kSA3-|>KN5kTO~@sfS+cDoU&=BL$aA2St}z1BSHCJe&KhlF%` zJb&P!1TIxo9n)#Go*>-o^=|3*e3i;2&d3P;%dwUKfs>j?gSWM{K`xX1J_vXqfdZY* zF*rCFh&|kSOG^uwG4mc2JRpFgsCT2IqwshMl+*1##W Date: Sun, 14 Apr 2013 17:04:55 +0200 Subject: [PATCH 279/817] added basic cell table --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/cell.cpp | 20 ++++++++++++++++++++ apps/opencs/model/world/cell.hpp | 17 +++++++++++++++++ apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/idcollection.hpp | 6 ++++-- apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadcell.cpp | 18 ++++++++++++++++++ components/esm/loadcell.hpp | 3 +++ 13 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/world/cell.cpp create mode 100644 apps/opencs/model/world/cell.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5c15938bd..efc3551fd 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -22,7 +22,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid data record idcollection commands columnbase scriptcontext + universalid data record idcollection commands columnbase scriptcontext cell ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp new file mode 100644 index 000000000..759468fa8 --- /dev/null +++ b/apps/opencs/model/world/cell.cpp @@ -0,0 +1,20 @@ + +#include "cell.hpp" + +#include + +void CSMWorld::Cell::load (ESM::ESMReader &esm) +{ + mName = mId; + + ESM::Cell::load (esm, true); /// \todo set this to false, once the bug in ESM::Cell::load is fixed + + if (!(mData.mFlags & Interior)) + { + std::ostringstream stream; + + stream << "#" << mData.mX << " " << mData.mY; + + mId = stream.str(); + } +} \ No newline at end of file diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp new file mode 100644 index 000000000..6a9676a55 --- /dev/null +++ b/apps/opencs/model/world/cell.hpp @@ -0,0 +1,17 @@ +#ifndef CSM_WOLRD_CELL_H +#define CSM_WOLRD_CELL_H + +#include + +namespace CSMWorld +{ + /// \brief Wrapper for Cell record + struct Cell : public ESM::Cell + { + std::string mId; + + void load (ESM::ESMReader &esm); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 9f6b186c0..83702b05c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -119,6 +119,11 @@ CSMWorld::Data::Data() mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); + mCells.addColumn (new StringIdColumn); + mCells.addColumn (new RecordStateColumn); + mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); + mCells.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -130,6 +135,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); + addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell); } CSMWorld::Data::~Data() @@ -248,6 +254,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSpells() return mSpells; } +const CSMWorld::IdCollection& CSMWorld::Data::getCells() const +{ + return mCells; +} + +CSMWorld::IdCollection& CSMWorld::Data::getCells() +{ + return mCells; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -293,6 +309,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_REGN: mRegions.load (reader, base); break; case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; case ESM::REC_SPEL: mSpells.load (reader, base); break; + case ESM::REC_CELL: mCells.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index d7b69ba5e..03a2448f1 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -20,6 +20,7 @@ #include "idcollection.hpp" #include "universalid.hpp" +#include "cell.hpp" class QAbstractItemModel; @@ -38,6 +39,7 @@ namespace CSMWorld IdCollection mRegions; IdCollection mBirthsigns; IdCollection mSpells; + IdCollection mCells; std::vector mModels; std::map mModelIndex; @@ -98,6 +100,10 @@ namespace CSMWorld IdCollection& getSpells(); + const IdCollection& getCells() const; + + IdCollection& getCells(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 3bf53349e..4afe9cbaa 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -325,10 +325,10 @@ namespace CSMWorld { std::string id = reader.getHNOString ("NAME"); - int index = searchId (id); - if (reader.isNextSub ("DELE")) { + int index = searchId (id); + reader.skipRecord(); if (index==-1) @@ -354,6 +354,8 @@ namespace CSMWorld record.mId = id; record.load (reader); + int index = searchId (record.mId); + if (index==-1) { // new record diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 11f487788..c0241bc38 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -28,6 +28,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -45,6 +46,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 5586b22e7..9b52aded1 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -55,7 +55,9 @@ namespace CSMWorld Type_Birthsigns, Type_Birthsign, Type_Spells, - Type_Spell + Type_Spell, + Type_Cells, + Type_Cell }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index dfdcb1036..a684b85c5 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -125,6 +125,10 @@ void CSVDoc::View::setupWorldMenu() QAction *spells = new QAction (tr ("Spells"), this); connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); world->addAction (spells); + + QAction *cells = new QAction (tr ("Cells"), this); + connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView())); + world->addAction (cells); } void CSVDoc::View::setupUi() @@ -325,6 +329,11 @@ void CSVDoc::View::addSpellsSubView() addSubView (CSMWorld::UniversalId::Type_Spells); } +void CSVDoc::View::addCellsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Cells); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 9241efbb9..a240d3b01 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -133,6 +133,8 @@ namespace CSVDoc void addBirthsignsSubView(); void addSpellsSubView(); + + void addCellsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 8f7887f3b..0ce3d3d6d 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -26,6 +26,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_Spells, + CSMWorld::UniversalId::Type_Cells, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 5cbf1de2b..77e4d3691 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -356,4 +356,22 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) return true; } + void Cell::blank() + { + mName.clear(); + mRegion.clear(); + mWater = 0; + mWaterInt = false; + mMapColor = 0; + mNAM0 = 0; + + mData.mFlags = 0; + mData.mX = 0; + mData.mY = 0; + + mAmbi.mAmbient = 0; + mAmbi.mSunlight = 0; + mAmbi.mFog = 0; + mAmbi.mFogDensity = 0; + } } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 44412b5eb..d7f64817f 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -140,6 +140,9 @@ struct Cell * Since they are comparably rare, we use a separate method for this. */ static bool getNextMVRF(ESMReader &esm, MovedCellRef &mref); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 71148121a2d5327156d16fb0ceb779117cc90a96 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 14 Apr 2013 17:10:37 +0200 Subject: [PATCH 280/817] added flag columns to cell table --- apps/opencs/model/world/data.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 83702b05c..604b55109 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -123,6 +123,9 @@ CSMWorld::Data::Data() mCells.addColumn (new RecordStateColumn); mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn); + mCells.addColumn (new FlagColumn ("Sleep forbidden", ESM::Cell::NoSleep)); + mCells.addColumn (new FlagColumn ("Interior Water", ESM::Cell::HasWater)); + mCells.addColumn (new FlagColumn ("Interior Sky", ESM::Cell::QuasiEx)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 48f46e505cb9a1a1e7adde097ba1c69132eee54b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Apr 2013 17:37:39 +0200 Subject: [PATCH 281/817] Look in exterior cells first (chargen_crate_01_empty is in the prison ship but also outside of it, the one outside needs to be disabled) --- apps/openmw/mwworld/cells.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 4838cfefa..87ac1c6d7 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -165,6 +165,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce else return Ptr(); } + MWWorld::Ptr ptr; if (MWWorld::LiveCellRef *ref = cell.mActivators.find (name)) @@ -246,16 +247,16 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) } // Then check cells that are already listed - for (std::map::iterator iter = mInteriors.begin(); - iter!=mInteriors.end(); ++iter) + for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); + iter!=mExteriors.end(); ++iter) { Ptr ptr = getPtrAndCache (name, iter->second); if (!ptr.isEmpty()) - return ptr; + return ptr; } - for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); - iter!=mExteriors.end(); ++iter) + for (std::map::iterator iter = mInteriors.begin(); + iter!=mInteriors.end(); ++iter) { Ptr ptr = getPtrAndCache (name, iter->second); if (!ptr.isEmpty()) @@ -266,7 +267,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) const MWWorld::Store &cells = mStore.get(); MWWorld::Store::iterator iter; - for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter) + for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter) { Ptr::CellStore *cellStore = getCellStore (&(*iter)); @@ -276,7 +277,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) return ptr; } - for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter) + for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter) { Ptr::CellStore *cellStore = getCellStore (&(*iter)); From a57fbbb168a68201b22b63f218397e2758d2de22 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Apr 2013 17:51:17 +0200 Subject: [PATCH 282/817] Fix wrong detection of diseases --- apps/openmw/mwmechanics/spells.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index e2da7cdc8..e10dcdc93 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -80,7 +80,7 @@ namespace MWMechanics const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - if (spell->mData.mFlags & ESM::Spell::ST_Disease) + if (spell->mData.mType == ESM::Spell::ST_Disease) return true; } @@ -94,7 +94,7 @@ namespace MWMechanics const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - if (spell->mData.mFlags & ESM::Spell::ST_Blight) + if (spell->mData.mType == ESM::Spell::ST_Blight) return true; } From b2b953d2a88d844c35ef58b3b5303d12d8541b48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 14 Apr 2013 19:34:55 +0200 Subject: [PATCH 283/817] added region column to cell table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 9242e8a23..f1d8d4ae6 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -748,6 +748,31 @@ namespace CSMWorld return true; } }; + + template + struct RegionColumn : public Column + { + RegionColumn() : Column ("Region", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mRegion.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mRegion = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 604b55109..dedbfc4e7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -126,6 +126,7 @@ CSMWorld::Data::Data() mCells.addColumn (new FlagColumn ("Sleep forbidden", ESM::Cell::NoSleep)); mCells.addColumn (new FlagColumn ("Interior Water", ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn ("Interior Sky", ESM::Cell::QuasiEx)); + mCells.addColumn (new RegionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 4e0233cf06384472ef49f47de87fcccc1068066c Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 14 Apr 2013 21:42:37 +0200 Subject: [PATCH 284/817] Base local rotations implementation --- .../mwscript/transformationextensions.cpp | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6c4fb0f4b..922353974 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -553,26 +553,30 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why + Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why (probably framerate) runtime.pop(); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + float *objRot = ptr.getRefData().getPosition().rot; - //Axis in morrowind are inverted - if (axis == "y") + if (axis == "x") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + objRot[0]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_X));; } - else if (axis == "x") + else if (axis == "y") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + objRot[1]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Y)); } else if (axis == "z") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + objRot[2]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Z)); } + else throw std::runtime_error ("invalid rotation axis: " + axis); } From bf8bc989fc0184f59aa40f9d3a028d4fad6f749b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 12:52:20 -0700 Subject: [PATCH 285/817] Recognize and partly handle NiBSParticleNode --- components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 1 + components/nifogre/ogrenifloader.cpp | 12 +++++++----- components/nifogre/skeleton.cpp | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 3b41e96a7..2c4f3506e 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -208,7 +208,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiNode", &construct , RC_NiNode }, { "AvoidNode", &construct , RC_NiNode }, - { "NiBSParticleNode", &construct , RC_NiNode }, + { "NiBSParticleNode", &construct , RC_NiBSParticleNode }, { "NiBSAnimationNode", &construct , RC_NiBSAnimationNode }, { "NiBillboardNode", &construct , RC_NiNode }, { "NiTriShape", &construct , RC_NiTriShape }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 361af3f64..97b10503e 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -39,6 +39,7 @@ enum RecordType RC_NiTriShape, RC_NiRotatingParticles, RC_NiAutoNormalParticles, + RC_NiBSParticleNode, RC_NiCamera, RC_NiTexturingProperty, RC_NiMaterialProperty, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 631d39728..1ed5e24a3 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -469,7 +469,7 @@ class NIFObjectLoader static void createParticleSystem(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, ObjectList &objectlist, - const Nif::Node *partnode, int flags, int animflags) + const Nif::Node *partnode, int flags, int partflags) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -539,7 +539,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags, int animflags) + ObjectList &objectlist, int flags, int animflags, int partflags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -552,6 +552,8 @@ class NIFObjectLoader if(node->recType == Nif::RC_NiBSAnimationNode) animflags |= node->flags; + else if(node->recType == Nif::RC_NiBSParticleNode) + partflags |= node->flags; else flags |= node->flags; @@ -622,7 +624,7 @@ class NIFObjectLoader if((node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { - createParticleSystem(name, group, sceneMgr, objectlist, node, flags, animflags); + createParticleSystem(name, group, sceneMgr, objectlist, node, flags, partflags); } const Nif::NiNode *ninode = dynamic_cast(node); @@ -632,7 +634,7 @@ class NIFObjectLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags, partflags); } } } @@ -679,7 +681,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist, flags, 0); + createObjects(name, group, sceneMgr, node, objectlist, flags, 0, 0); } }; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 28df4894d..75bc90715 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -165,6 +165,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ + node->recType == Nif::RC_NiBSParticleNode || node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles From 7000a1aa3eba373f33741e7f208e1af8bd6c45e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 13:50:55 -0700 Subject: [PATCH 286/817] Add a ParticleSystemController --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 1ed5e24a3..69f14b663 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -329,6 +329,35 @@ public: typedef DefaultFunction Function; }; +class ParticleSystemController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::ParticleSystem *mParticleSys; + float mEmitStart; + float mEmitStop; + + public: + Value(Ogre::ParticleSystem *psys, const Nif::NiParticleSystemController *pctrl) + : mParticleSys(psys) + , mEmitStart(pctrl->startTime) + , mEmitStop(pctrl->stopTime) + { + } + + Ogre::Real getValue() const + { return 0.0f; } + + void setValue(Ogre::Real value) + { + mParticleSys->setEmitting(value >= mEmitStart && value < mEmitStop); + } + }; + + typedef DefaultFunction Function; +}; /** Object creator for NIFs. This is the main class responsible for creating @@ -521,6 +550,13 @@ class NIFObjectLoader Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } + + Ogre::ControllerValueRealPtr srcval((partflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&0x20))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } From f9dee25fd1c0218fd40ac11e2b3406bbb70283b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 16:56:35 -0700 Subject: [PATCH 287/817] Store the base skeleton entity in MWRender::Animation --- apps/openmw/mwrender/animation.cpp | 21 ++++++++++++--------- apps/openmw/mwrender/animation.hpp | 3 ++- apps/openmw/mwrender/npcanimation.cpp | 5 ++--- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a849b20ef..d6f762ab7 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -33,6 +33,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mController(NULL) , mInsert(NULL) + , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) @@ -65,7 +66,7 @@ Animation::~Animation() void Animation::setAnimationSources(const std::vector &names) { - if(!mObjectList.mSkelBase) + if(!mSkelBase) return; Ogre::SceneManager *sceneMgr = mInsert->getCreator(); @@ -81,7 +82,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.clear(); Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { @@ -127,7 +128,7 @@ void Animation::setAnimationSources(const std::vector &names) if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); } for(int i = 0;i < skel->getNumAnimations();i++) @@ -152,7 +153,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model mObjectList = NifOgre::Loader::createObjects(mInsert, model); if(mObjectList.mSkelBase) { - Ogre::AnimationStateSet *aset = mObjectList.mSkelBase->getAllAnimationStates(); + mSkelBase = mObjectList.mSkelBase; + + Ogre::AnimationStateSet *aset = mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -164,7 +167,7 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); @@ -182,9 +185,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model Ogre::Node *Animation::getNode(const std::string &name) { - if(mObjectList.mSkelBase) + if(mSkelBase) { - Ogre::SkeletonInstance *skel = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); if(skel->hasBone(name)) return skel->getBone(name); } @@ -508,11 +511,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) for(size_t i = 0;i < mCurrentControllers->size();i++) (*mCurrentControllers)[i].update(); - if(mObjectList.mSkelBase) + if(mSkelBase) { // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. - mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + mSkelBase->getAllAnimationStates()->_notifyDirty(); } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 029c56523..32344a2c0 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -42,7 +42,8 @@ protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; - Ogre::SceneNode* mInsert; + Ogre::SceneNode *mInsert; + Ogre::Entity *mSkelBase; NifOgre::ObjectList mObjectList; std::map mTextKeys; Ogre::Node *mAccumRoot; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 96220f47d..a2446b867 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -359,8 +359,7 @@ void NpcAnimation::updateParts(bool forceupdate) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { - NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, - mInsert, model); + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); for(size_t i = 0;i < objects.mEntities.size();i++) { objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); @@ -408,7 +407,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mObjectList.mSkelBase->getSkeleton(); + const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; From 2693b785362ec30ba729c7807ad20d7a0d2d74f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Apr 2013 02:56:23 +0200 Subject: [PATCH 288/817] Add initial player inventory when new game is started --- apps/openmw/engine.cpp | 1 + apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/armor.cpp | 19 +++++++----------- apps/openmw/mwclass/armor.hpp | 5 +++-- apps/openmw/mwclass/clothing.cpp | 20 ++++--------------- apps/openmw/mwclass/clothing.hpp | 3 ++- apps/openmw/mwclass/weapon.cpp | 8 ++++---- apps/openmw/mwclass/weapon.hpp | 3 ++- .../mwmechanics/mechanicsmanagerimp.cpp | 12 +++++++++++ apps/openmw/mwworld/actionequip.cpp | 10 +++++++--- apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 3 ++- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++++++--- apps/openmw/mwworld/worldimp.hpp | 1 + 15 files changed, 62 insertions(+), 46 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 69e3cdc53..4472b205f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -368,6 +368,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, mActivationDistanceOverride)); + MWBase::Environment::get().getWorld()->setupPlayer(mNewGame); //Load translation data mTranslationDataStorage.setEncoder(mEncoder); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39e985890..bee744386 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -321,6 +321,7 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual bool vanityRotateCamera(float * rot) = 0; + virtual void setupPlayer(bool newGame) = 0; virtual void renderPlayer() = 0; virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 6791138d3..8a8f72c88 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,7 +292,7 @@ namespace MWClass ref->mBase = record; } - int Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); @@ -317,10 +317,7 @@ namespace MWClass { if((*itr).mPart == ESM::PRT_Head) { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - return 0; + return std::make_pair(0, "#{sNotifyMessage13}"); } } } @@ -331,9 +328,7 @@ namespace MWClass { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - return 0; + return std::make_pair(0, "#{sNotifyMessage14}"); } } } @@ -344,7 +339,7 @@ namespace MWClass MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(weapon == invStore.end()) - return 1; + return std::make_pair(1,""); if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || @@ -354,12 +349,12 @@ namespace MWClass weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - return 3; + return std::make_pair(3,""); } - return 1; + return std::make_pair(1,""); } } - return 1; + return std::make_pair(1,""); } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 703d3af1e..9b8e9dd14 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,8 +67,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; - ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 6c231e0c6..3072f852d 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,7 +238,7 @@ namespace MWClass ref->mBase = record; } - int Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); @@ -260,12 +260,7 @@ namespace MWClass for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_Head) - { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - return 0; - } + return std::make_pair(0, "#{sNotifyMessage13}"); } } @@ -274,19 +269,12 @@ namespace MWClass for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) - { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); - } - - return 0; - } + return std::make_pair(0, "#{sNotifyMessage15}"); } } } } - return 1; + return std::make_pair (1, ""); } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 1be42adbd..a6de0cb4f 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,8 +61,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index fbac6d89e..6c6b3daa6 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,7 +384,7 @@ namespace MWClass ref->mBase = record; } - int Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); @@ -402,12 +402,12 @@ namespace MWClass ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - return 2; + return std::make_pair (2, ""); } - return 1; + return std::make_pair (1, ""); } } - return 0; + return std::make_pair (0, ""); } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 314f6bc21..05b1aee22 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,8 +67,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4a2a2ecc6..d34c4b97f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -155,6 +155,18 @@ namespace MWMechanics stat.setCurrent (stat.getModified()); creatureStats.setDynamic (i, stat); } + + // unequip any items that may not be equipped. we need this for when the race is changed to a beast race + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + for (int i=0; i result = MWWorld::Class::get (object).canBeEquipped (object, actor); + + // display error message if the player tried to equip something + if (!result.second.empty() && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) + MWBase::Environment::get().getWindowManager()->messageBox(result.second); + + switch(result.first) { case 0: return; @@ -48,8 +54,6 @@ namespace MWWorld assert(it != invStore.end()); - std::string npcRace = actor.get()->mBase->mRace; - bool equipped = false; // equip the item in the first free slot diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4321fc46b..451f0c5c1 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -264,9 +264,9 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - int Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - return 1; + return std::make_pair (1, ""); } void Class::adjustPosition(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 32941c633..b901950e3 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -245,8 +245,9 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 5495d6a02..ac5586266 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -186,7 +186,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - switch(MWWorld::Class::get (test).canBeEquipped (test, npc)) + switch(MWWorld::Class::get (test).canBeEquipped (test, npc).first) { case 0: continue; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e70aedd55..424f6f508 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -24,6 +24,7 @@ #include "manualref.hpp" #include "cellfunctors.hpp" #include "containerstore.hpp" +#include "inventorystore.hpp" using namespace Ogre; @@ -210,9 +211,6 @@ namespace MWWorld mStore.setUp(); - mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); - mRendering->attachCameraTo(mPlayer->getPlayer()); - // global variables mGlobalVariables = new Globals (mStore); @@ -1369,6 +1367,18 @@ namespace MWWorld return mRendering->vanityRotateCamera(rot); } + void World::setupPlayer(bool newGame) + { + const ESM::NPC* player = mStore.get().find ("player"); + mPlayer = new MWWorld::Player (player, *this); + mRendering->attachCameraTo(mPlayer->getPlayer()); + if (newGame) + { + MWWorld::Class::get(mPlayer->getPlayer()).getContainerStore(mPlayer->getPlayer()).fill(player->mInventory, "", mStore); + MWWorld::Class::get(mPlayer->getPlayer()).getInventoryStore(mPlayer->getPlayer()).autoEquip (mPlayer->getPlayer()); + } + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7b12babee..99e7cc79d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -363,6 +363,7 @@ namespace MWWorld virtual bool vanityRotateCamera(float * rot); + virtual void setupPlayer(bool newGame); virtual void renderPlayer(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); From 69084139aaf2c4711061dd62a84666d6f34c6d10 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 17:58:21 -0700 Subject: [PATCH 289/817] Use an array of objectlists, instead of one base objectlist and an array of 'animation sources' --- apps/openmw/mwrender/activatoranimation.cpp | 10 +- apps/openmw/mwrender/animation.cpp | 136 +++++++------------- apps/openmw/mwrender/animation.hpp | 14 +- apps/openmw/mwrender/creatureanimation.cpp | 21 ++- apps/openmw/mwrender/npcanimation.cpp | 27 ++-- 5 files changed, 75 insertions(+), 133 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 4630208b4..27ddce339 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -27,9 +27,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) std::string mesh = "meshes\\" + ref->mBase->mModel; createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *ent = mObjectList.mEntities[i]; + Ogre::Entity *ent = mObjectLists[0].mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,14 +38,12 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->setVisibilityFlags(RV_Misc); - part->setRenderQueueGroup(RQG_Alpha); } - setAnimationSource(mesh); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d6f762ab7..30bcd3c4c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -55,68 +55,45 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - destroyObjectList(sceneMgr, mObjectList); - - for(size_t i = 0;i < mAnimationSources.size();i++) - destroyObjectList(sceneMgr, mAnimationSources[i]); - mAnimationSources.clear(); + for(size_t i = 0;i < mObjectLists.size();i++) + destroyObjectList(sceneMgr, mObjectLists[i]); + mObjectLists.clear(); } } -void Animation::setAnimationSources(const std::vector &names) +void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) { - if(!mSkelBase) - return; - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + assert(!mInsert); + mInsert = node->createChildSceneNode(); + assert(mInsert); - mCurrentControllers = &mObjectList.mControllers; - mCurrentAnim = NULL; - mCurrentKeys = NULL; - mAnimVelocity = 0.0f; - mAccumRoot = NULL; - mNonAccumRoot = NULL; - mTextKeys.clear(); - for(size_t i = 0;i < mAnimationSources.size();i++) - destroyObjectList(sceneMgr, mAnimationSources[i]); - mAnimationSources.clear(); + mObjectLists.resize(1); - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); - std::vector::const_iterator nameiter; - for(nameiter = names.begin();nameiter != names.end();nameiter++) + mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); + if(mObjectLists[0].mSkelBase) { - mAnimationSources.push_back(NifOgre::Loader::createObjectBase(sceneMgr, *nameiter)); - if(!mAnimationSources.back().mSkelBase) + mSkelBase = mObjectLists[0].mSkelBase; + + Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) { - std::cerr<< "Failed to get skeleton source "<<*nameiter < *dstval = dynamic_cast*>(objects.mControllers[i].getDestination().getPointer()); - if(!dstval) continue; - - const Ogre::String &trgtname = dstval->getNode()->getName(); - if(!skelinst->hasBone(trgtname)) continue; - - Ogre::Bone *bone = skelinst->getBone(trgtname); - dstval->setNode(bone); + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); } - for(size_t i = 0;i < objects.mControllers.size();i++) - { - if(objects.mControllers[i].getSource().isNull()) - objects.mControllers[i].setSource(ctrlval); - } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). + Ogre::SkeletonInstance *skelinst = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); - Ogre::Entity *ent = objects.mSkelBase; - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); + boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { Ogre::Bone *bone = boneiter.getNext(); @@ -143,43 +120,14 @@ void Animation::setAnimationSources(const std::vector &names) break; } } -} - -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) -{ - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectList = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectList.mSkelBase) - { - mSkelBase = mObjectList.mSkelBase; - - Ogre::AnimationStateSet *aset = mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - state->setLoop(false); - } - - // Set the bones as manually controlled since we're applying the - // transformations manually (needed if we want to apply an animation - // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); - } Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectList.mControllers.size();i++) + for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) { - if(mObjectList.mControllers[i].getSource().isNull()) - mObjectList.mControllers[i].setSource(ctrlval); + if(mObjectLists[0].mControllers[i].getSource().isNull()) + mObjectLists[0].mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectList.mControllers; + mCurrentControllers = &mObjectLists[0].mControllers; } @@ -197,9 +145,9 @@ Ogre::Node *Animation::getNode(const std::string &name) bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) + for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - if(iter->mSkelBase->hasAnimationState(anim)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(anim)) return true; } return false; @@ -449,7 +397,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) + for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { if(iter->mSkelBase->hasAnimationState(groupname)) { @@ -513,9 +461,19 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mSkelBase) { - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mSkelBase->getAllAnimationStates()->_notifyDirty(); + const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + for(size_t i = 0;i < mObjectLists.size();i++) + { + Ogre::Entity *ent = mObjectLists[i].mSkelBase; + if(!ent) continue; + + Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); + if(skelsrc != skeldst) + updateSkeletonInstance(skelsrc, skeldst); + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + ent->getAllAnimationStates()->_notifyDirty(); + } } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 32344a2c0..3c7433db9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -44,15 +44,13 @@ protected: Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; - NifOgre::ObjectList mObjectList; + std::vector mObjectLists; std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::vector mAnimationSources; - std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -83,16 +81,6 @@ protected: bool handleEvent(float time, const std::string &evt); - /* Specifies a list of skeleton names to use as animation sources. */ - void setAnimationSources(const std::vector &names); - - /* Specifies a single skeleton name to use as an animation source. */ - void setAnimationSource(const std::string &name) - { - std::vector names(1, name); - setAnimationSources(names); - } - void createObjectList(Ogre::SceneNode *node, const std::string &model); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index c714a2372..7084974b8 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,10 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), model); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + std::vector names; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + names.push_back("meshes\\base_anim.nif"); + names.push_back(model); + + createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *ent = mObjectList.mEntities[i]; + Ogre::Entity *ent = mObjectLists[0].mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,19 +43,13 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->setVisibilityFlags(RV_Actors); part->setRenderQueueGroup(RQG_Alpha); } - - std::vector names; - if((ref->mBase->mFlags&ESM::Creature::Biped)) - names.push_back("meshes\\base_anim.nif"); - names.push_back(model); - setAnimationSources(names); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a2446b867..a713ae79e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,10 +96,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - createObjectList(node, smodel); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + std::vector skelnames(1, smodel); + if(!mNpc->isMale() && !isBeast) + skelnames.push_back("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + skelnames.push_back("meshes\\argonian_swimkna.nif"); + if(mNpc->mModel.length() > 0) + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + + createObjectList(node, smodel/*skelnames*/); + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *base = mObjectList.mEntities[i]; + Ogre::Entity *base = mObjectLists[0].mEntities[i]; base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if (mVisibilityFlags != 0) @@ -111,9 +119,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if(mVisibilityFlags != 0) @@ -121,15 +129,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor part->setRenderQueueGroup(RQG_Alpha); } - std::vector skelnames(1, smodel); - if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); - else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); - if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - setAnimationSources(skelnames); - forceUpdate(); } From 7fcaffefb09dc8f9a95660e9513ef88540d71b3c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Apr 2013 03:13:25 +0200 Subject: [PATCH 290/817] Fixed travel window to use the rotation part of ESM::Position --- apps/openmw/mwgui/travelwindow.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 8eaa0d8c6..8389db067 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -141,21 +141,22 @@ namespace MWGui int x,y; bool interior = _sender->getUserString("interior") == "y"; MWBase::Environment::get().getWorld()->positionToIndex(pos.pos[0],pos.pos[1],x,y); - MWWorld::CellStore* cell; - if(interior) cell = MWBase::Environment::get().getWorld()->getInterior(cellname); + if(interior) + MWBase::Environment::get().getWorld()->changeToInteriorCell(cellname, pos); else { - cell = MWBase::Environment::get().getWorld()->getExterior(x,y); - ESM::Position PlayerPos = player.getRefData().getPosition(); - float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) ); - int time = int(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); - for(int i = 0;i < time;i++) + ESM::Position playerPos = player.getRefData().getPosition(); + float d = Ogre::Vector3(pos.pos[0], pos.pos[1], 0).distance( + Ogre::Vector3(playerPos.pos[0], playerPos.pos[1], 0)); + int hours = static_cast(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); + for(int i = 0;i < hours;i++) { MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats (); } - MWBase::Environment::get().getWorld()->advanceTime(time); + MWBase::Environment::get().getWorld()->advanceTime(hours); + + MWBase::Environment::get().getWorld()->changeToExteriorCell(pos); } - MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); MWWorld::Class::get(player).adjustPosition(player); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); From 972481f63f7ef724364b6cf9672aac50fc558788 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 15 Apr 2013 16:45:53 +0200 Subject: [PATCH 291/817] Working rotate, rotateworld --- apps/openmw/mwbase/windowmanager.hpp | 2 + apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 + apps/openmw/mwscript/docs/vmformat.txt | 4 +- .../mwscript/transformationextensions.cpp | 56 +++++++++++++++++-- apps/openmw/mwworld/worldimp.cpp | 6 ++ apps/openmw/mwworld/worldimp.hpp | 2 + 8 files changed, 73 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 976d7d84c..b34117df2 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,6 +251,8 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; + + virtual int getFPS() const = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39e985890..94a30d759 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -230,6 +230,8 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; + virtual void localRotateObject (const MWWorld::Ptr& ptr, float rotation, Ogre::Vector3 axis) = 0; + virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f994683a6..b3a080bf2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1200,3 +1200,8 @@ void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); } + +int WindowManager::getFPS() const +{ + return mFPS; +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3c9fc586a..3a7296b5b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -248,6 +248,8 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); + virtual int getFPS() const; + private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7810c2874..b7ee2d31c 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -320,5 +320,7 @@ op 0x20001fd: IsWerewolf op 0x20001fe: IsWerewolf, explicit reference op 0x20001ff: Rotate op 0x2000200: Rotate, explicit reference +op 0x2000201: RotateWorld +op 0x2000202: RotateWorld, explicit reference -opcodes 0x2000201-0x3ffffff unused +opcodes 0x2000203-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 922353974..41bacf110 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -13,6 +13,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -549,11 +550,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = R()(runtime); + const MWWorld::Ptr& ptr = R()(runtime); std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why (probably framerate) + Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; @@ -562,19 +563,22 @@ namespace MWScript { objRot[0]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_X));; + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { objRot[1]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Y)); + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { objRot[2]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Z)); + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } else @@ -582,6 +586,43 @@ namespace MWScript } }; + template + class OpRotateWorld : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + runtime.pop(); + + float *objRot = ptr.getRefData().getPosition().rot; + + float ax = Ogre::Radian(objRot[0]).valueDegrees(); + float ay = Ogre::Radian(objRot[1]).valueDegrees(); + float az = Ogre::Radian(objRot[2]).valueDegrees(); + + if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + } + else if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -610,6 +651,8 @@ namespace MWScript const int opcodeModScaleExplicit = 0x20001e4; const int opcodeRotate = 0x20001ff; const int opcodeRotateExplicit = 0x2000200; + const int opcodeRotateWorld = 0x2000201; + const int opcodeRotateWorldExplicit = 0x2000202; void registerExtensions (Compiler::Extensions& extensions) { @@ -628,6 +671,7 @@ namespace MWScript extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); + extensions.registerInstruction("rotateworld","cf",opcodeRotateWorld,opcodeRotateWorldExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -659,6 +703,8 @@ namespace MWScript interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); interpreter.installSegment5(opcodeRotate,new OpRotate); interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); + interpreter.installSegment5(opcodeRotateWorld,new OpRotateWorld); + interpreter.installSegment5(opcodeRotateWorldExplicit,new OpRotateWorld); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 11ccd8f2f..c5ebbb306 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -826,6 +826,12 @@ namespace MWWorld } } + void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) + { + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + mPhysics->rotateObject(ptr); + } + void World::adjustPosition(const Ptr &ptr) { Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7b12babee..59a359b6b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -254,6 +254,8 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + virtual void localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis); + virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. From 763308868d501bc7bd7102d6a442855f8c155f1b Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 15 Apr 2013 17:45:18 +0200 Subject: [PATCH 292/817] Fixed rotation speed --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ----- apps/openmw/mwgui/windowmanagerimp.hpp | 2 -- apps/openmw/mwscript/transformationextensions.cpp | 5 ++--- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b34117df2..976d7d84c 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,8 +251,6 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; - - virtual int getFPS() const = 0; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b3a080bf2..f994683a6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1200,8 +1200,3 @@ void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); } - -int WindowManager::getFPS() const -{ - return mFPS; -} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3a7296b5b..3c9fc586a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -248,8 +248,6 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); - virtual int getFPS() const; - private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 41bacf110..8ac5a7802 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -13,7 +13,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -554,7 +553,7 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; @@ -597,7 +596,7 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; From 1b1f9f7921d91bc2c2c853cfc0b0f5c71fba0574 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 18:55:28 -0700 Subject: [PATCH 293/817] Allow multiple ObjectLists to be created for Animations. addObjectList may not currently be called outside of the related constructor. --- apps/openmw/mwrender/activatoranimation.cpp | 13 ++-- apps/openmw/mwrender/animation.cpp | 80 +++++++++++++-------- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 17 +++-- apps/openmw/mwrender/npcanimation.cpp | 39 +++------- components/nifogre/ogrenifloader.cpp | 7 +- components/nifogre/ogrenifloader.hpp | 2 +- 7 files changed, 82 insertions(+), 78 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 27ddce339..1f9a2e23c 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -24,12 +24,13 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->mBase->mModel; + const std::string name = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), name, false); + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,9 +39,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Misc); part->setRenderQueueGroup(RQG_Alpha); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30bcd3c4c..979046ea0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -36,7 +36,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) - , mAccumulate(Ogre::Vector3::ZERO) + , mAccumulate(0.0f) , mLastPosition(0.0f) , mCurrentControllers(NULL) , mCurrentKeys(NULL) @@ -62,20 +62,24 @@ Animation::~Animation() } -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) +void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly) { - assert(!mInsert); - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectLists.resize(1); - - mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectLists[0].mSkelBase) + if(!mInsert) { - mSkelBase = mObjectLists[0].mSkelBase; + mInsert = node->createChildSceneNode(); + assert(mInsert); + } + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + NifOgre::ObjectList &objlist = mObjectLists.back(); + if(objlist.mSkelBase) + { + if(!mSkelBase) + mSkelBase = objlist.mSkelBase; + + Ogre::AnimationStateSet *aset = objlist.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -87,11 +91,28 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = objlist.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + if(mSkelBase != objlist.mSkelBase) + { + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(!dstval) continue; + + const Ogre::String &trgtname = dstval->getNode()->getName(); + if(!baseinst->hasBone(trgtname)) continue; + + Ogre::Bone *bone = baseinst->getBone(trgtname); + dstval->setNode(bone); + } + } + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -120,14 +141,14 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model break; } } - - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { - if(mObjectLists[0].mControllers[i].getSource().isNull()) - mObjectLists[0].mControllers[i].setSource(ctrlval); + if(objlist.mControllers[i].getSource().isNull()) + objlist.mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectLists[0].mControllers; + + if(!mCurrentControllers || (*mCurrentControllers).size() == 0) + mCurrentControllers = &objlist.mControllers; } @@ -399,9 +420,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); + Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); + mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; @@ -456,20 +478,22 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mCurrentControllers->size();i++) + + for(size_t i = 0;i < (*mCurrentControllers).size();i++) (*mCurrentControllers)[i].update(); if(mSkelBase) { - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); - for(size_t i = 0;i < mObjectLists.size();i++) + const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - Ogre::Entity *ent = mObjectLists[i].mSkelBase; + Ogre::Entity *ent = iter->mSkelBase; if(!ent) continue; - Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); - if(skelsrc != skeldst) - updateSkeletonInstance(skelsrc, skeldst); + Ogre::SkeletonInstance *inst = ent->getSkeleton(); + if(baseinst != inst) + updateSkeletonInstance(baseinst, inst); + // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. ent->getAllAnimationStates()->_notifyDirty(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3c7433db9..79262f3c5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -81,7 +81,7 @@ protected: bool handleEvent(float time, const std::string &evt); - void createObjectList(Ogre::SceneNode *node, const std::string &model); + void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); public: diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7084974b8..a48b8da9f 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,15 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - std::vector names; if((ref->mBase->mFlags&ESM::Creature::Biped)) - names.push_back("meshes\\base_anim.nif"); - names.push_back(model); + addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); - createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), model, false); + + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -43,11 +43,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a713ae79e..3ef357440 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,38 +96,13 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - std::vector skelnames(1, smodel); + addObjectList(node, smodel, true); if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); + addObjectList(node, "meshes\\base_anim_female.nif", true); else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); + addObjectList(node, "meshes\\argonian_swimkna.nif", true); if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - - createObjectList(node, smodel/*skelnames*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) - { - Ogre::Entity *base = mObjectLists[0].mEntities[i]; - - base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if (mVisibilityFlags != 0) - base->setVisibilityFlags(mVisibilityFlags); - - for(unsigned int j=0; j < base->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = base->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) - { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; - - part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if(mVisibilityFlags != 0) - part->setVisibilityFlags(mVisibilityFlags); - part->setRenderQueueGroup(RQG_Alpha); - } + addObjectList(node, "meshes\\"+mNpc->mModel, true); forceUpdate(); } @@ -406,14 +381,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; if(!ent) continue; - updateSkeletonInstance(skelsrc, ent->getSkeleton()); + updateSkeletonInstance(baseinst, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); } + return ret; } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 69f14b663..04cdb142f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -800,12 +800,15 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena } -ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string name, const std::string &group) +ObjectList Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group, 0xC0000000); + + if(objectlist.mSkelBase) + parentNode->attachObject(objectlist.mSkelBase); return objectlist; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index fa5182aea..e3bb55064 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -69,7 +69,7 @@ public: std::string name, const std::string &group="General"); - static ObjectList createObjectBase(Ogre::SceneManager *sceneMgr, + static ObjectList createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); }; From 4ce98e9bd65ff2035e2f36e89a90cb6f892472fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 20:37:10 -0700 Subject: [PATCH 294/817] Store iterators for start and stop keys --- apps/openmw/mwrender/animation.cpp | 51 ++++++++++++------------------ apps/openmw/mwrender/animation.hpp | 7 ++-- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 979046ea0..11876a247 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -38,11 +38,10 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) + , mCurrentAnim(NULL) , mCurrentControllers(NULL) , mCurrentKeys(NULL) - , mCurrentAnim(NULL) , mCurrentTime(0.0f) - , mStopTime(0.0f) , mPlaying(false) , mLooping(false) , mAnimVelocity(0.0f) @@ -313,35 +312,26 @@ Ogre::Vector3 Animation::updatePosition() void Animation::reset(const std::string &start, const std::string &stop) { - mNextKey = mCurrentKeys->begin(); + mStartKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != start) - mNextKey++; - if(mNextKey != mCurrentKeys->end()) - mCurrentTime = mNextKey->first; + while(mStartKey != mCurrentKeys->end() && mStartKey->second != start) + mStartKey++; + if(mStartKey != mCurrentKeys->end()) + mCurrentTime = mStartKey->first; else { - mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != "start") - mNextKey++; - if(mNextKey != mCurrentKeys->end()) - mCurrentTime = mNextKey->first; - else - { - mNextKey = mCurrentKeys->begin(); - mCurrentTime = 0.0f; - } + mStartKey = mCurrentKeys->begin(); + mCurrentTime = mStartKey->first; } + mNextKey = mStartKey; if(stop.length() > 0) { - NifOgre::TextKeyMap::const_iterator stopKey = mNextKey; - while(stopKey != mCurrentKeys->end() && stopKey->second != stop) - stopKey++; - if(stopKey != mCurrentKeys->end()) - mStopTime = stopKey->first; - else - mStopTime = mCurrentAnim->getLength(); + mStopKey = mStartKey; + while(mStopKey != mCurrentKeys->end() && mStopKey->second != stop) + mStopKey++; + if(mStopKey == mCurrentKeys->end()) + mStopKey--; } if(mNonAccumRoot) @@ -390,7 +380,7 @@ bool Animation::handleEvent(float time, const std::string &evt) { if(mLooping) { - reset("loop start", ""); + reset("loop start"); if(mCurrentTime >= time) return false; } @@ -400,7 +390,7 @@ bool Animation::handleEvent(float time, const std::string &evt) { if(mLooping) { - reset("loop start", ""); + reset("loop start"); if(mCurrentTime >= time) return false; return true; @@ -455,13 +445,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) while(mCurrentAnim && mPlaying) { float targetTime = mCurrentTime + timepassed; - if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) + if(mNextKey->first > targetTime) { - mCurrentTime = std::min(mStopTime, targetTime); + mCurrentTime = targetTime; if(mNonAccumRoot) movement += updatePosition(); - mPlaying = (mLooping || mStopTime > mCurrentTime); - timepassed = targetTime - mCurrentTime; break; } @@ -472,7 +460,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) mCurrentTime = time; if(mNonAccumRoot) movement += updatePosition(); - mPlaying = (mLooping || mStopTime > mCurrentTime); + + mPlaying = (mLooping || mStopKey->first > mCurrentTime); timepassed = targetTime - mCurrentTime; if(!handleEvent(time, evt)) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 79262f3c5..f8ddceeaa 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -50,13 +50,14 @@ protected: Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; + Ogre::Animation *mCurrentAnim; std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; - Ogre::Animation *mCurrentAnim; float mCurrentTime; - float mStopTime; bool mPlaying; bool mLooping; @@ -77,7 +78,7 @@ protected: * moving anything, and set the end time to the specified stop marker. If * the marker is not found, it resets to the beginning or end respectively. */ - void reset(const std::string &start, const std::string &stop); + void reset(const std::string &start, const std::string &stop=std::string()); bool handleEvent(float time, const std::string &evt); From 36170c5374402f06b49bcf63d7c856572072ebda Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Apr 2013 01:20:32 -0700 Subject: [PATCH 295/817] Use flag enums instead of hard-coded hex values --- components/nif/node.hpp | 18 +++++++------ components/nifbullet/bulletnifloader.cpp | 6 ++--- components/nifogre/ogrenifloader.cpp | 32 +++++++++++++----------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 9c345baab..917bc8add 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -128,13 +128,17 @@ struct NiNode : Node NodeList children; NodeList effects; - /* Known NiNode flags: - 0x01 hidden - 0x02 use mesh for collision - 0x04 use bounding box for collision (?) - 0x08 unknown, but common - 0x20, 0x40, 0x80 unknown - */ + enum Flags { + Flag_Hidden = 0x0001, + Flag_MeshCollision = 0x0002, + Flag_BBoxCollision = 0x0004 + }; + enum BSAnimFlags { + AnimFlag_AutoPlay = 0x0020 + }; + enum BSParticleFlags { + ParticleFlag_AutoPlay = 0x0020 + }; void read(NIFStream *nif) { diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 6bd43f6e3..a3eff95c3 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -255,9 +255,9 @@ void ManualBulletShapeLoader::handleNiTriShape(btTriangleMesh* mesh, const Nif:: assert(shape != NULL); // Interpret flags - bool hidden = (flags & 0x01) != 0; // Not displayed - bool collide = (flags & 0x02) != 0; // Use mesh for collision - bool bbcollide = (flags & 0x04) != 0; // Use bounding box for collision + bool hidden = (flags&Nif::NiNode::Flag_Hidden) != 0; + bool collide = (flags&Nif::NiNode::Flag_MeshCollision) != 0; + bool bbcollide = (flags&Nif::NiNode::Flag_BBoxCollision) != 0; // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 04cdb142f..2e77adb08 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -394,7 +394,7 @@ class NIFObjectLoader NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); Ogre::Entity *entity = sceneMgr->createEntity(fullname); - entity->setVisible(!(flags&0x01)); + entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); objectlist.mEntities.push_back(entity); if(objectlist.mSkelBase) @@ -417,10 +417,11 @@ class NIFObjectLoader const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -551,10 +552,11 @@ class NIFObjectLoader objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - Ogre::ControllerValueRealPtr srcval((partflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -568,7 +570,7 @@ class NIFObjectLoader objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - partsys->setVisible(!(flags&0x01)); + partsys->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); objectlist.mParticles.push_back(partsys); } @@ -627,10 +629,11 @@ class NIFObjectLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -641,10 +644,11 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } From 518cb0e3b7a181462bb7044ae966a9bcf18659c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 16 Apr 2013 12:12:04 +0200 Subject: [PATCH 296/817] added another abstraction layer to ID access in IdCollection --- apps/opencs/model/world/idcollection.hpp | 123 +++++++++++++---------- 1 file changed, 72 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 4afe9cbaa..7052b300e 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -79,8 +79,29 @@ namespace CSMWorld virtual void load (ESM::ESMReader& reader, bool base) = 0; }; - ///< \brief Collection of ID-based records + ///< \brief Access to ID field in records template + struct IdAccessor + { + std::string& getId (ESXRecordT& record); + + const std::string getId (const ESXRecordT& record) const; + }; + + template + std::string& IdAccessor::getId (ESXRecordT& record) + { + return record.mId; + } + + template + const std::string IdAccessor::getId (const ESXRecordT& record) const + { + return record.mId; + } + + ///< \brief Collection of ID-based records + template > class IdCollection : public IdCollectionBase { std::vector > mRecords; @@ -150,21 +171,21 @@ namespace CSMWorld void addColumn (Column *column); }; - template - IdCollection::IdCollection() + template + IdCollection::IdCollection() {} - template - IdCollection::~IdCollection() + template + IdCollection::~IdCollection() { for (typename std::vector *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) delete *iter; } - template - void IdCollection::add (const ESXRecordT& record) + template + void IdCollection::add (const ESXRecordT& record) { - std::string id = Misc::StringUtils::lowerCase(record.mId); + std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record)); std::map::iterator iter = mIndex.find (id); @@ -183,20 +204,20 @@ namespace CSMWorld } } - template - int IdCollection::getSize() const + template + int IdCollection::getSize() const { return mRecords.size(); } - template - std::string IdCollection::getId (int index) const + template + std::string IdCollection::getId (int index) const { - return mRecords.at (index).get().mId; + return IdAccessorT().getId (mRecords.at (index).get()); } - template - int IdCollection::getIndex (const std::string& id) const + template + int IdCollection::getIndex (const std::string& id) const { int index = searchId (id); @@ -206,38 +227,38 @@ namespace CSMWorld return index; } - template - int IdCollection::getColumns() const + template + int IdCollection::getColumns() const { return mColumns.size(); } - template - QVariant IdCollection::getData (int index, int column) const + template + QVariant IdCollection::getData (int index, int column) const { return mColumns.at (column)->get (mRecords.at (index)); } - template - void IdCollection::setData (int index, int column, const QVariant& data) + template + void IdCollection::setData (int index, int column, const QVariant& data) { return mColumns.at (column)->set (mRecords.at (index), data); } - template - const ColumnBase& IdCollection::getColumn (int column) const + template + const ColumnBase& IdCollection::getColumn (int column) const { return *mColumns.at (column); } - template - void IdCollection::addColumn (Column *column) + template + void IdCollection::addColumn (Column *column) { mColumns.push_back (column); } - template - void IdCollection::merge() + template + void IdCollection::merge() { for (typename std::vector >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter) iter->merge(); @@ -245,16 +266,16 @@ namespace CSMWorld purge(); } - template - void IdCollection::purge() + template + void IdCollection::purge() { mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(), std::mem_fun_ref (&Record::isErased) // I want lambda :( ), mRecords.end()); } - template - void IdCollection::removeRows (int index, int count) + template + void IdCollection::removeRows (int index, int count) { mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count); @@ -278,17 +299,17 @@ namespace CSMWorld } } - template - void IdCollection::appendBlankRecord (const std::string& id) + template + void IdCollection::appendBlankRecord (const std::string& id) { ESXRecordT record; - record.mId = id; + IdAccessorT().getId (record) = id; record.blank(); add (record); } - template - int IdCollection::searchId (const std::string& id) const + template + int IdCollection::searchId (const std::string& id) const { std::string id2 = Misc::StringUtils::lowerCase(id); @@ -300,28 +321,28 @@ namespace CSMWorld return iter->second; } - template - void IdCollection::replace (int index, const RecordBase& record) + template + void IdCollection::replace (int index, const RecordBase& record) { mRecords.at (index) = dynamic_cast&> (record); } - template - void IdCollection::appendRecord (const RecordBase& record) + template + void IdCollection::appendRecord (const RecordBase& record) { mRecords.push_back (dynamic_cast&> (record)); mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (getId (record)), mRecords.size()-1)); } - template - std::string IdCollection::getId (const RecordBase& record) const + template + std::string IdCollection::getId (const RecordBase& record) const { const Record& record2 = dynamic_cast&> (record); - return (record2.isModified() ? record2.mModified : record2.mBase).mId; + return IdAccessorT().getId (record2.isModified() ? record2.mModified : record2.mBase); } - template - void IdCollection::load (ESM::ESMReader& reader, bool base) + template + void IdCollection::load (ESM::ESMReader& reader, bool base) { std::string id = reader.getHNOString ("NAME"); @@ -351,10 +372,10 @@ namespace CSMWorld else { ESXRecordT record; - record.mId = id; + IdAccessorT().getId (record) = id; record.load (reader); - int index = searchId (record.mId); + int index = searchId (IdAccessorT().getId (record)); if (index==-1) { @@ -378,15 +399,15 @@ namespace CSMWorld } } - template - const Record& IdCollection::getRecord (const std::string& id) const + template + const Record& IdCollection::getRecord (const std::string& id) const { int index = getIndex (id); return mRecords.at (index); } - template - const Record& IdCollection::getRecord (int index) const + template + const Record& IdCollection::getRecord (int index) const { return mRecords.at (index); } From 1e92ffc3147229b9d1b08e972b4372f7b8ca9f49 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:17:19 +0200 Subject: [PATCH 297/817] Added rotation layer --- .../mwscript/transformationextensions.cpp | 27 +++++++++---------- apps/openmw/mwworld/refdata.cpp | 12 ++++++++- apps/openmw/mwworld/refdata.hpp | 10 +++++++ apps/openmw/mwworld/scene.cpp | 7 +++++ apps/openmw/mwworld/worldimp.cpp | 6 +++-- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8ac5a7802..e2d701268 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -102,6 +102,11 @@ namespace MWScript } else throw std::runtime_error ("invalid ration axis: " + axis); + + //Local rotations clear + ptr.getRefData().getLocalRotation().rot[0]=0; + ptr.getRefData().getLocalRotation().rot[1]=0; + ptr.getRefData().getLocalRotation().rot[2]=0; } }; @@ -148,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]+ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]+ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]+ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -556,27 +561,19 @@ namespace MWScript Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float *objRot = ptr.getRefData().getPosition().rot; - if (axis == "x") { - objRot[0]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) - MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); + ptr.getRefData().getLocalRotation().rot[0]+=rotation; + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { - objRot[1]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) + ptr.getRefData().getLocalRotation().rot[1]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { - objRot[2]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) + ptr.getRefData().getLocalRotation().rot[2]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 4be287810..db565c451 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -19,6 +19,7 @@ namespace MWWorld mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; + mLocalRotation = refData.mLocalRotation; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -34,7 +35,11 @@ namespace MWWorld RefData::RefData (const ESM::CellRef& cellRef) : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0) - {} + { + mLocalRotation.rot[0]=0; + mLocalRotation.rot[1]=0; + mLocalRotation.rot[2]=0; + } RefData::RefData (const RefData& refData) : mBaseNode(0), mCustomData (0) @@ -141,6 +146,11 @@ namespace MWWorld return mPosition; } + LocalRotation& RefData::getLocalRotation() + { + return mLocalRotation; + } + void RefData::setCustomData (CustomData *data) { delete mCustomData; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 3a6e0fc9f..c3aa647ec 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,6 +5,8 @@ #include "../mwscript/locals.hpp" +#include + namespace Ogre { class SceneNode; @@ -18,6 +20,10 @@ namespace ESM namespace MWWorld { + struct LocalRotation{ + float rot[3]; + }; + class CustomData; class RefData @@ -34,6 +40,8 @@ namespace MWWorld ESM::Position mPosition; + LocalRotation mLocalRotation; + CustomData *mCustomData; void copy (const RefData& refData); @@ -78,6 +86,8 @@ namespace MWWorld ESM::Position& getPosition(); + LocalRotation& getLocalRotation(); + void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \æ data is /// transferred to this. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 439f76131..b11b59ac6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -50,6 +50,13 @@ namespace rendering.addObject(ptr); class_.insertObject(ptr, physics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + + //To keep local-rotations + const float *local = ptr.getRefData().getLocalRotation().rot; + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[0], Ogre::Vector3::UNIT_X); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[1], Ogre::Vector3::UNIT_Y); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[2], Ogre::Vector3::UNIT_Z); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); class_.adjustPosition(ptr); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 52d0d953a..69bcad619 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -826,8 +826,10 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) { - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); - mPhysics->rotateObject(ptr); + if (ptr.getRefData().getBaseNode() != 0) { + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + mPhysics->rotateObject(ptr); + } } void World::adjustPosition(const Ptr &ptr) From 1fd59d0ce0c63e893f6203a723579d25dc3ec7c9 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:21:54 +0200 Subject: [PATCH 298/817] Removed useless include --- apps/openmw/mwworld/refdata.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index c3aa647ec..77ceb3721 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,8 +5,6 @@ #include "../mwscript/locals.hpp" -#include - namespace Ogre { class SceneNode; From e3a9f73eb6008159b3ba1fa1fa15451050360407 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:40:34 +0200 Subject: [PATCH 299/817] Improved getangle script behaviour --- apps/openmw/mwscript/transformationextensions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index e2d701268..beb6c3d8c 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -153,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]+ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]+ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]+ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); } else throw std::runtime_error ("invalid ration axis: " + axis); From 60fadaeaf0368df6c6bafafbabe24a233a74d124 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Tue, 16 Apr 2013 20:16:22 -0400 Subject: [PATCH 300/817] Cleaned up includes in implementation files --- apps/openmw/mwgui/alchemywindow.cpp | 2 -- apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/birth.cpp | 2 -- apps/openmw/mwgui/charactercreation.cpp | 2 -- apps/openmw/mwgui/class.cpp | 5 ----- apps/openmw/mwgui/companionwindow.cpp | 1 - apps/openmw/mwgui/confirmationdialog.cpp | 5 ----- apps/openmw/mwgui/console.cpp | 6 ------ apps/openmw/mwgui/container.cpp | 12 ------------ apps/openmw/mwgui/countdialog.cpp | 3 --- apps/openmw/mwgui/cursor.cpp | 2 -- apps/openmw/mwgui/dialogue.cpp | 9 +-------- apps/openmw/mwgui/formatting.cpp | 1 - apps/openmw/mwgui/hud.cpp | 10 ---------- apps/openmw/mwgui/inventorywindow.cpp | 13 ------------- apps/openmw/mwgui/journalwindow.cpp | 3 --- apps/openmw/mwgui/levelupdialog.cpp | 2 -- apps/openmw/mwgui/loadingscreen.cpp | 9 --------- apps/openmw/mwgui/mainmenu.cpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 4 ---- apps/openmw/mwgui/merchantrepair.cpp | 3 --- apps/openmw/mwgui/quickkeysmenu.cpp | 4 ---- apps/openmw/mwgui/race.cpp | 6 ------ apps/openmw/mwgui/review.cpp | 6 ------ apps/openmw/mwgui/settingswindow.cpp | 6 ------ apps/openmw/mwgui/soulgemdialog.cpp | 1 - apps/openmw/mwgui/spellbuyingwindow.cpp | 4 ---- apps/openmw/mwgui/spellcreationdialog.cpp | 8 -------- apps/openmw/mwgui/spellicons.cpp | 5 ----- apps/openmw/mwgui/spellwindow.cpp | 8 -------- apps/openmw/mwgui/statswindow.cpp | 6 ------ apps/openmw/mwgui/tooltips.cpp | 7 ------- apps/openmw/mwgui/tradewindow.cpp | 1 - apps/openmw/mwgui/travelwindow.cpp | 7 ------- apps/openmw/mwgui/waitdialog.cpp | 4 ---- apps/openmw/mwgui/widgets.cpp | 2 -- apps/openmw/mwgui/windowbase.cpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 23 +---------------------- apps/openmw/mwgui/windowpinnablebase.cpp | 2 -- 39 files changed, 2 insertions(+), 196 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index a6121c234..24a4e205b 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -8,8 +8,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/containerstore.hpp" namespace { diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 655a832c1..9189e4a63 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -10,7 +10,6 @@ namespace MWGui { - class AlchemyWindow : public WindowBase, public ContainerBase { public: diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 133bbd32f..9c3ebdc7d 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -3,8 +3,6 @@ #include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 0dd6502c6..28f6d13ee 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -5,8 +5,6 @@ #include "class.hpp" #include "birth.hpp" #include "review.hpp" -#include "dialogue.hpp" -#include "mode.hpp" #include "inventorywindow.hpp" #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 6edad9e83..e4d32c933 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -1,11 +1,6 @@ #include "class.hpp" -#include - #include -#include - -#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 0a20c471a..22afc42f6 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -2,7 +2,6 @@ #include -#include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 904468f88..f431f2f64 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -1,10 +1,5 @@ #include "confirmationdialog.hpp" -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - namespace MWGui { ConfirmationDialog::ConfirmationDialog() : diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 1aebe57da..bd1b0fe7a 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -1,13 +1,7 @@ - #include "console.hpp" -#include -#include - #include -#include "../mwworld/esmstore.hpp" - #include "../mwscript/extensions.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 8ee4754a3..d15a5acd3 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -1,11 +1,5 @@ #include "container.hpp" -#include -#include -#include -#include -#include - #include #include "../mwbase/environment.hpp" @@ -13,15 +7,9 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwclass/container.hpp" - -#include "widgets.hpp" #include "countdialog.hpp" #include "tradewindow.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index d017cc198..fe5122455 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -2,9 +2,6 @@ #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - namespace MWGui { CountDialog::CountDialog() : diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index b0d164bed..c069eca15 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -2,13 +2,11 @@ #include #include -#include #include #include #include - namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index f3c11752e..392f64126 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -1,18 +1,11 @@ #include "dialogue.hpp" -#include -#include - -#include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 7f28e9e17..b21b903bd 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -3,7 +3,6 @@ #include #include "../mwscript/interpretercontext.hpp" -#include "../mwworld/ptr.hpp" #include #include diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 84526a28d..988bcfc24 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,24 +1,14 @@ #include "hud.hpp" -#include - -#include -#include - #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwgui/widgets.hpp" - #include "inventorywindow.hpp" -#include "container.hpp" #include "console.hpp" #include "spellicons.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 40c228fd5..e5e20b778 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,28 +1,15 @@ #include "inventorywindow.hpp" -#include -#include -#include -#include - #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/containerstore.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/inventorystore.hpp" -#include "widgets.hpp" #include "bookwindow.hpp" #include "scrollwindow.hpp" #include "spellwindow.hpp" diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 35a687cc4..23588a4af 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -4,9 +4,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/soundmanager.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwdialogue/journalentry.hpp" namespace { diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index fc1317e90..5857db4d2 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -8,12 +8,10 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/fallback.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/stat.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 858c3f36e..3b341574d 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -1,25 +1,16 @@ #include "loadingscreen.hpp" #include -#include #include #include -#include - - -#include #include #include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include - - namespace MWGui { diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 5402d3542..ebd31d92c 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -3,7 +3,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 17834be93..1ac1c2448 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -2,12 +2,8 @@ #include -#include -#include #include -#include - #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 53148cb3f..a98051c28 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -9,10 +9,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/containerstore.hpp" -#include "../mwworld/class.hpp" -#include "list.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 2deb37d30..a44f1791c 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -2,13 +2,9 @@ #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwworld/player.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" #include "../mwgui/inventorywindow.hpp" #include "../mwgui/bookwindow.hpp" diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9a0d8a029..c031ad6b6 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -1,19 +1,13 @@ #include "race.hpp" -#include -#include - #include #include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "widgets.hpp" #include "tooltips.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 562bf9774..31f5d737b 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -1,17 +1,11 @@ #include "review.hpp" -#include - -#include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "widgets.hpp" #include "tooltips.hpp" #undef min diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 93b82e374..39ee4e01d 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1,24 +1,18 @@ #include "settingswindow.hpp" #include -#include #include -#include #include #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwrender/renderingmanager.hpp" - #include "confirmationdialog.hpp" namespace diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index 4530a13d0..b95eec0b6 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -1,6 +1,5 @@ #include "soulgemdialog.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "messagebox.hpp" diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 7d634df8d..cb2007565 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -1,7 +1,5 @@ #include "spellbuyingwindow.hpp" -#include - #include #include "../mwbase/environment.hpp" @@ -11,9 +9,7 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index e1df9f9cd..45cf1b0aa 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -4,22 +4,14 @@ #include "../mwbase/windowmanager.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/class.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" - #include "tooltips.hpp" -#include "widgets.hpp" #include "class.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 206db51ed..e762cc610 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -1,9 +1,5 @@ #include "spellicons.hpp" -#include -#include -#include - #include #include "../mwbase/world.hpp" @@ -14,7 +10,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwmechanics/activespells.hpp" #include "../mwmechanics/creaturestats.hpp" #include "tooltips.hpp" diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d07f9ca54..bd1fef12b 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -1,22 +1,14 @@ #include "spellwindow.hpp" -#include #include #include -#include "../mwworld/esmstore.hpp" - -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" #include "spellicons.hpp" diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index a00ec167d..3439ff31c 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -1,14 +1,9 @@ #include "statswindow.hpp" -#include -#include -#include - #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" @@ -18,7 +13,6 @@ #include "tooltips.hpp" - using namespace MWGui; const int StatsWindow::sLineHeight = 18; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2250ffd0b..b72d27aea 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -2,18 +2,11 @@ #include -#include - -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/class.hpp" - #include "mapwindow.hpp" -#include "widgets.hpp" #include "inventorywindow.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f3f226974..23bb6554f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -9,7 +9,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 8eaa0d8c6..780ffa056 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -1,22 +1,15 @@ #include "travelwindow.hpp" -#include - #include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" - -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index a84b9203a..ad2b4710c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,7 +1,5 @@ #include "waitdialog.hpp" -#include - #include #include @@ -11,9 +9,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/timestamp.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index dd3206ed6..e6c8b1d77 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -9,8 +9,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/esmstore.hpp" - #undef min #undef max diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index c41bcb7ce..cc74579ab 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,7 +1,5 @@ #include "windowbase.hpp" -#include - #include "../mwbase/windowmanager.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f2ded8813..154234bee 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1,39 +1,20 @@ #include "windowmanagerimp.hpp" -#include -#include - -#include - #include #include -#include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/inputmanager.hpp" -#include "../mwworld/ptr.hpp" -#include "../mwworld/cellstore.hpp" - #include "console.hpp" #include "journalwindow.hpp" #include "charactercreation.hpp" -#include "textinput.hpp" -#include "review.hpp" #include "dialogue.hpp" #include "dialoguehistory.hpp" -#include "mapwindow.hpp" #include "statswindow.hpp" #include "messagebox.hpp" -#include "container.hpp" -#include "inventorywindow.hpp" #include "tooltips.hpp" #include "scrollwindow.hpp" #include "bookwindow.hpp" -#include "list.hpp" #include "hud.hpp" #include "mainmenu.hpp" #include "countdialog.hpp" @@ -48,17 +29,15 @@ #include "loadingscreen.hpp" #include "levelupdialog.hpp" #include "waitdialog.hpp" -#include "spellcreationdialog.hpp" #include "enchantingdialog.hpp" #include "trainingwindow.hpp" -#include "imagebutton.hpp" #include "exposedwindow.hpp" #include "cursor.hpp" -#include "spellicons.hpp" #include "merchantrepair.hpp" #include "repair.hpp" #include "soulgemdialog.hpp" #include "companionwindow.hpp" +#include "inventorywindow.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 56868306a..53ba1b9fd 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -1,7 +1,5 @@ #include "windowpinnablebase.hpp" -#include "../mwbase/windowmanager.hpp" - #include "exposedwindow.hpp" using namespace MWGui; From 3def2a0f453932c8fed8e83bc2654082e6ab0c46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Apr 2013 19:16:45 -0700 Subject: [PATCH 301/817] Treat the particle random values as the max differential --- components/nifogre/ogrenifloader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 2e77adb08..c5cc45ae9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -433,11 +433,11 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, - partctrl->velocity+partctrl->velocityRandom); + emitter->setParticleVelocity(partctrl->velocity - partctrl->velocityRandom*0.5f, + partctrl->velocity + partctrl->velocityRandom*0.5f); emitter->setEmissionRate(partctrl->emitRate); - emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, - partctrl->lifetime+partctrl->lifetimeRandom); + emitter->setTimeToLive(partctrl->lifetime - partctrl->lifetimeRandom*0.5f, + partctrl->lifetime + partctrl->lifetimeRandom*0.5f); emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); From c1ec16986bc396bc611154d992cad25fe3dea503 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 17 Apr 2013 12:04:05 +0200 Subject: [PATCH 302/817] add cmake fix for compiling with binutils >= 2.23 which requires explicit linking for dl and Xt --- apps/launcher/CMakeLists.txt | 6 ++++++ apps/openmw/CMakeLists.txt | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index eb93d71e7..0c93474da 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -102,3 +102,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(omwlauncher gcov) endif() + +# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream +if (UNIX AND NOT APPLE) +target_link_libraries(omwlauncher dl Xt) +endif() + diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3334e7865..f4fdcb390 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -122,6 +122,12 @@ if (UNIX AND NOT APPLE) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) endif() +# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream +if (UNIX AND NOT APPLE) +target_link_libraries(openmw dl Xt) +endif() + + if(APPLE) find_library(CARBON_FRAMEWORK Carbon) find_library(COCOA_FRAMEWORK Cocoa) From 547f77031db127fae46b374c94fccc854d08b067 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Apr 2013 17:05:54 +0200 Subject: [PATCH 303/817] Fix crash when disabling objects in a previously loaded cell, then coming back to that cell and leaving again --- apps/openmw/mwrender/actors.cpp | 4 ++++ apps/openmw/mwworld/cellfunctors.hpp | 6 ++++-- apps/openmw/mwworld/scene.cpp | 29 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 644d3613b..566b6fa81 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -94,6 +94,9 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr) bool Actors::deleteObject (const MWWorld::Ptr& ptr) { + if (mAllActors.find(ptr) == mAllActors.end()) + return false; + mRendering->removeWaterRippleEmitter (ptr); delete mAllActors[ptr]; @@ -139,6 +142,7 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) Ogre::SceneNode *base = celliter->second; base->removeAndDestroyAllChildren(); mRend.getScene()->destroySceneNode(base); + mCellSceneNodes.erase(celliter); } } diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp index 8bba898ce..4b1f70096 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -13,8 +13,8 @@ namespace ESM namespace MWWorld { - /// List all (Ogre-)handles. - struct ListHandles + /// List all (Ogre-)handles, then reset RefData::mBaseNode to 0. + struct ListAndResetHandles { std::vector mHandles; @@ -23,6 +23,8 @@ namespace MWWorld Ogre::SceneNode* handle = data.getBaseNode(); if (handle) mHandles.push_back (handle); + + data.setBaseNode(0); return true; } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 439f76131..b9b0aa19c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -76,27 +76,28 @@ namespace MWWorld void Scene::unloadCell (CellStoreCollection::iterator iter) { std::cout << "Unloading cell\n"; - ListHandles functor; + ListAndResetHandles functor; - (*iter)->forEach(functor); + (*iter)->forEach(functor); { // silence annoying g++ warning for (std::vector::const_iterator iter2 (functor.mHandles.begin()); - iter2!=functor.mHandles.end(); ++iter2){ - Ogre::SceneNode* node = *iter2; + iter2!=functor.mHandles.end(); ++iter2) + { + Ogre::SceneNode* node = *iter2; mPhysics->removeObject (node->getName()); } + } - if ((*iter)->mCell->isExterior()) - { - ESM::Land* land = - MWBase::Environment::get().getWorld()->getStore().get().search( - (*iter)->mCell->getGridX(), - (*iter)->mCell->getGridY() - ); - if (land) - mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() ); - } + if ((*iter)->mCell->isExterior()) + { + ESM::Land* land = + MWBase::Environment::get().getWorld()->getStore().get().search( + (*iter)->mCell->getGridX(), + (*iter)->mCell->getGridY() + ); + if (land) + mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() ); } mRendering.removeCell(*iter); From 0341a9e7781342e321744e1976f2a1918521806d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Apr 2013 20:57:22 +0200 Subject: [PATCH 304/817] Fix a gcc 4.8 warning --- apps/openmw/mwrender/videoplayer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 2cbc85cd3..87ae8175d 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -788,8 +788,8 @@ void VideoState::decode_thread_loop(VideoState *self) // main decode loop while(!self->quit) { - if((self->audio_st >= 0 && self->audioq.size > MAX_AUDIOQ_SIZE) || - (self->video_st >= 0 && self->videoq.size > MAX_VIDEOQ_SIZE)) + if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) || + (self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE)) { boost::this_thread::sleep(boost::posix_time::milliseconds(10)); continue; From c519fc360ddaeb13872fd761c267123440a88b7e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 00:19:34 +0200 Subject: [PATCH 305/817] Move away from fixed record names for body parts --- apps/esmtool/record.cpp | 2 +- apps/openmw/mwgui/race.cpp | 132 +++++++------------------- apps/openmw/mwgui/race.hpp | 7 +- apps/openmw/mwrender/npcanimation.cpp | 109 +++++++++++++-------- components/esm/loadarmo.hpp | 4 +- components/esm/loadbody.cpp | 4 +- components/esm/loadbody.hpp | 6 +- 7 files changed, 118 insertions(+), 146 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e16ade6e2..b7cbbc4ea 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -439,7 +439,7 @@ void Record::print() template<> void Record::print() { - std::cout << " Name: " << mData.mName << std::endl; + std::cout << " Race: " << mData.mRace << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Type: " << meshTypeLabel(mData.mData.mType) << " (" << (int)mData.mData.mType << ")" << std::endl; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index c031ad6b6..25bae999b 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -24,36 +24,6 @@ int wrap(int index, int max) else return index; } - -int countParts(const std::string &part, const std::string &race, bool male) -{ - /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs - const MWWorld::Store &store = - MWBase::Environment::get().getWorld()->getStore().get(); - - std::string prefix = - "b_n_" + race + ((male) ? "_m_" : "_f_") + part; - - std::string suffix; - suffix.reserve(prefix.size() + 3); - - int count = -1; - do { - ++count; - suffix = "_" + (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - - if (count == 0 && part == "hair") { - count = -1; - do { - ++count; - suffix = (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - } - return count; -} } RaceDialog::RaceDialog() @@ -61,8 +31,6 @@ RaceDialog::RaceDialog() , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) - , mFaceCount(10) - , mHairCount(14) , mCurrentAngle(0) { // Centre dialog @@ -227,67 +195,28 @@ void RaceDialog::onSelectNextGender(MyGUI::Widget*) void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) { - do - mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); - while (!isFacePlayable()); + mFaceIndex = wrap(mFaceIndex - 1, mAvailableHeads.size()); updatePreview(); } void RaceDialog::onSelectNextFace(MyGUI::Widget*) { - do - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); - while (!isFacePlayable()); + mFaceIndex = wrap(mFaceIndex + 1, mAvailableHeads.size()); updatePreview(); } void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) { - do - mHairIndex = wrap(mHairIndex - 1, mHairCount); - while (!isHairPlayable()); + mHairIndex = wrap(mHairIndex - 1, mAvailableHairs.size()); updatePreview(); } void RaceDialog::onSelectNextHair(MyGUI::Widget*) { - do - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isHairPlayable()); + mHairIndex = wrap(mHairIndex + 1, mAvailableHairs.size()); updatePreview(); } -bool RaceDialog::isFacePlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(prefix + "head_" + headIndex) == 0) - return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -bool RaceDialog::isHairPlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - if (parts.search(prefix + "hair_" + hairIndex) == 0) - return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) { if (_index == MyGUI::ITEM_NONE) @@ -308,18 +237,41 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) updateSpellPowers(); } +void RaceDialog::getBodyParts (int part, std::vector& out) +{ + out.clear(); + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + for (MWWorld::Store::iterator it = store.begin(); it != store.end(); ++it) + { + const ESM::BodyPart& bodypart = *it; + if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) + continue; + if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) + continue; + if (bodypart.mData.mPart != static_cast(part)) + continue; + if (mGenderIndex != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + continue; + bool firstPerson = (bodypart.mId.size() >= 3) + && bodypart.mId[bodypart.mId.size()-3] == '1' + && bodypart.mId[bodypart.mId.size()-2] == 's' + && bodypart.mId[bodypart.mId.size()-1] == 't'; + if (firstPerson) + continue; + if (Misc::StringUtils::ciEqual(bodypart.mRace, mCurrentRaceId)) + out.push_back(bodypart.mId); + } +} + void RaceDialog::recountParts() { - mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); - mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + getBodyParts(ESM::BodyPart::MP_Hair, mAvailableHairs); + getBodyParts(ESM::BodyPart::MP_Head, mAvailableHeads); mFaceIndex = 0; mHairIndex = 0; - - while (!isHairPlayable()) - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isFacePlayable()) - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); } // update widget content @@ -330,21 +282,9 @@ void RaceDialog::updatePreview() record.mRace = mCurrentRaceId; record.setIsMale(mGenderIndex == 0); - std::string prefix = - "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); + record.mHead = mAvailableHeads[mFaceIndex]; + record.mHair = mAvailableHairs[mHairIndex]; - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - record.mHead = prefix + "head_" + headIndex; - record.mHair = prefix + "hair_" + hairIndex; - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(record.mHair) == 0) { - record.mHair = prefix + "hair" + hairIndex; - } mPreview->setPrototype(record); } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 893c4c90b..1d48c67cd 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -76,8 +76,10 @@ namespace MWGui void updatePreview(); void recountParts(); - bool isHairPlayable(); - bool isFacePlayable(); + void getBodyParts (int part, std::vector& out); + + std::vector mAvailableHeads; + std::vector mAvailableHairs; MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; @@ -90,7 +92,6 @@ namespace MWGui std::vector mSpellPowerItems; int mGenderIndex, mFaceIndex, mHairIndex; - int mFaceCount, mHairCount; std::string mCurrentRaceId; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 96220f47d..ecc0869cc 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -305,56 +305,83 @@ void NpcAnimation::updateParts(bool forceupdate) if(mViewMode == VM_HeadOnly) return; - static const struct { - ESM::PartReferenceType type; - const char name[2][12]; - } PartTypeList[] = { - { ESM::PRT_Neck, { "neck", "" } }, - { ESM::PRT_Cuirass, { "chest", "" } }, - { ESM::PRT_Groin, { "groin", "" } }, - { ESM::PRT_RHand, { "hand", "hands" } }, - { ESM::PRT_LHand, { "hand", "hands" } }, - { ESM::PRT_RWrist, { "wrist", "" } }, - { ESM::PRT_LWrist, { "wrist", "" } }, - { ESM::PRT_RForearm, { "forearm", "" } }, - { ESM::PRT_LForearm, { "forearm", "" } }, - { ESM::PRT_RUpperarm, { "upper arm", "" } }, - { ESM::PRT_LUpperarm, { "upper arm", "" } }, - { ESM::PRT_RFoot, { "foot", "feet" } }, - { ESM::PRT_LFoot, { "foot", "feet" } }, - { ESM::PRT_RAnkle, { "ankle", "" } }, - { ESM::PRT_LAnkle, { "ankle", "" } }, - { ESM::PRT_RKnee, { "knee", "" } }, - { ESM::PRT_LKnee, { "knee", "" } }, - { ESM::PRT_RLeg, { "upper leg", "" } }, - { ESM::PRT_LLeg, { "upper leg", "" } }, - { ESM::PRT_Tail, { "tail", "" } } - }; + std::map bodypartMap; + bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck; + bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest; + bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin; + bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand; + bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand; + bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist; + bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist; + bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm; + bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm; + bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm; + bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm; + bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot; + bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot; + bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle; + bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle; + bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee; + bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee; + bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg; + bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg; + bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail; - const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) + + const int Flag_Female = 0x01; + const int Flag_FirstPerson = 0x02; + + int flags = 0; + if (!mNpc->isMale()) + flags |= Flag_Female; + if (mViewMode == VM_FirstPerson) + flags |= Flag_FirstPerson; + + // Remember body parts so we only have to search through the store once for each race/gender/viewmode combination + static std::map< std::pair , std::vector > sRaceMapping; + std::string race = Misc::StringUtils::lowerCase(mNpc->mRace); + std::pair thisCombination = std::make_pair(race, flags); + if (sRaceMapping.find(thisCombination) == sRaceMapping.end()) { - if(mPartPriorities[PartTypeList[i].type] < 1) + sRaceMapping[thisCombination].resize(ESM::PRT_Count); + for (int i=0; i &partStore = store.get(); + + for (MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) { - const ESM::BodyPart *part = NULL; - const MWWorld::Store &partStore = store.get(); - - if(!mNpc->isMale()) + const ESM::BodyPart& bodypart = *it; + if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) + continue; + if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) { - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]+ext); - if(part == 0) - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]+ext); + continue; } - if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]+ext); - if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]+ext); + if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + continue; + if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace)) + continue; - if(part) - addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); + bool firstPerson = (bodypart.mId.size() >= 3) + && bodypart.mId[bodypart.mId.size()-3] == '1' + && bodypart.mId[bodypart.mId.size()-2] == 's' + && bodypart.mId[bodypart.mId.size()-1] == 't'; + if (firstPerson != (mViewMode == VM_FirstPerson)) + continue; + for (std::map::iterator bIt = bodypartMap.begin(); bIt != bodypartMap.end(); ++bIt ) + if (bIt->second == bodypart.mData.mPart) + sRaceMapping[thisCombination][bIt->first] = &*it; } } + + for (int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part) + { + const ESM::BodyPart* bodypart = sRaceMapping[thisCombination][part]; + if (mPartPriorities[part] < 1 && bodypart) + addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel); + } } NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index a94ae6735..c18b4486d 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -38,7 +38,9 @@ enum PartReferenceType PRT_RPauldron = 23, PRT_LPauldron = 24, PRT_Weapon = 25, - PRT_Tail = 26 + PRT_Tail = 26, + + PRT_Count = 27 }; // Reference to body parts diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 831ad8b64..e95a8a860 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -9,13 +9,13 @@ namespace ESM void BodyPart::load(ESMReader &esm) { mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); + mRace = esm.getHNString("FNAM"); esm.getHNT(mData, "BYDT", 4); } void BodyPart::save(ESMWriter &esm) { esm.writeHNCString("MODL", mModel); - esm.writeHNCString("FNAM", mName); + esm.writeHNCString("FNAM", mRace); esm.writeHNT("BYDT", mData, 4); } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index c467b3625..3ad9b1b95 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -27,7 +27,9 @@ struct BodyPart MP_Knee = 11, MP_Upperleg = 12, MP_Clavicle = 13, - MP_Tail = 14 + MP_Tail = 14, + + MP_Count = 15 }; enum Flags @@ -52,7 +54,7 @@ struct BodyPart }; BYDTstruct mData; - std::string mId, mModel, mName; + std::string mId, mModel, mRace; void load(ESMReader &esm); void save(ESMWriter &esm); From 7eee86ab66f8b7fbd33e375418b6bdf44122dedf Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 17 Apr 2013 18:56:48 -0400 Subject: [PATCH 306/817] No more using namespace --- apps/openmw/mwgui/birth.cpp | 418 ++--- apps/openmw/mwgui/bookwindow.cpp | 261 +-- apps/openmw/mwgui/charactercreation.cpp | 1255 ++++++------- apps/openmw/mwgui/class.cpp | 1599 ++++++++-------- apps/openmw/mwgui/console.cpp | 31 +- apps/openmw/mwgui/container.cpp | 1220 ++++++------ apps/openmw/mwgui/dialogue.cpp | 912 ++++----- apps/openmw/mwgui/dialoguehistory.cpp | 104 +- apps/openmw/mwgui/formatting.cpp | 545 +++--- apps/openmw/mwgui/hud.cpp | 959 +++++----- apps/openmw/mwgui/list.cpp | 296 +-- apps/openmw/mwgui/mapwindow.cpp | 793 ++++---- apps/openmw/mwgui/messagebox.cpp | 747 ++++---- apps/openmw/mwgui/race.cpp | 822 ++++----- apps/openmw/mwgui/review.cpp | 658 +++---- apps/openmw/mwgui/scrollwindow.cpp | 128 +- apps/openmw/mwgui/statswindow.cpp | 1021 +++++----- apps/openmw/mwgui/textinput.cpp | 121 +- apps/openmw/mwgui/tooltips.cpp | 1416 +++++++------- apps/openmw/mwgui/widgets.cpp | 1676 ++++++++--------- apps/openmw/mwgui/windowmanagerimp.cpp | 2145 +++++++++++----------- apps/openmw/mwgui/windowpinnablebase.cpp | 39 +- 22 files changed, 8609 insertions(+), 8557 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 9c3ebdc7d..965606709 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -9,237 +9,239 @@ #include "widgets.hpp" -using namespace MWGui; -using namespace Widgets; - namespace { -bool sortBirthSigns(const std::pair& left, const std::pair& right) -{ - return left.second->mName.compare (right.second->mName) < 0; -} + bool sortBirthSigns(const std::pair& left, const std::pair& right) + { + return left.second->mName.compare (right.second->mName) < 0; + } } -BirthDialog::BirthDialog() - : WindowModal("openmw_chargen_birth.layout") +namespace MWGui { - // Centre dialog - center(); - getWidget(mSpellArea, "SpellArea"); + BirthDialog::BirthDialog() + : WindowModal("openmw_chargen_birth.layout") + { + // Centre dialog + center(); - getWidget(mBirthImage, "BirthsignImage"); + getWidget(mSpellArea, "SpellArea"); - getWidget(mBirthList, "BirthsignList"); - mBirthList->setScrollVisible(true); - mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + getWidget(mBirthImage, "BirthsignImage"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); + getWidget(mBirthList, "BirthsignList"); + mBirthList->setScrollVisible(true); + mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); - updateBirths(); - updateSpells(); -} - -void BirthDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); -void BirthDialog::open() -{ - WindowModal::open(); - updateBirths(); - updateSpells(); -} + updateBirths(); + updateSpells(); + } - -void BirthDialog::setBirthId(const std::string &birthId) -{ - mCurrentBirthId = birthId; - mBirthList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mBirthList->getItemCount(); - for (size_t i = 0; i < count; ++i) + void BirthDialog::setNextButtonShow(bool shown) { - if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void BirthDialog::open() + { + WindowModal::open(); + updateBirths(); + updateSpells(); + } + + + void BirthDialog::setBirthId(const std::string &birthId) + { + mCurrentBirthId = birthId; + mBirthList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mBirthList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mBirthList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; - } - } - - updateSpells(); -} - -// widget controls - -void BirthDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void BirthDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - const std::string *birthId = mBirthList->getItemDataAt(_index); - if (boost::iequals(mCurrentBirthId, *birthId)) - return; - - mCurrentBirthId = *birthId; - updateSpells(); -} - -// update widget content - -void BirthDialog::updateBirths() -{ - mBirthList->removeAllItems(); - - const MWWorld::Store &signs = - MWBase::Environment::get().getWorld()->getStore().get(); - - // sort by name - std::vector < std::pair > birthSigns; - - MWWorld::Store::iterator it = signs.begin(); - for (; it != signs.end(); ++it) - { - birthSigns.push_back(std::make_pair(it->mId, &(*it))); - } - std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); - - int index = 0; - for (std::vector >::const_iterator it2 = birthSigns.begin(); - it2 != birthSigns.end(); ++it2, ++index) - { - mBirthList->addItem(it2->second->mName, it2->first); - if (mCurrentBirthId.empty()) - { - mBirthList->setIndexSelected(index); - mCurrentBirthId = it2->first; - } - else if (boost::iequals(it2->first, mCurrentBirthId)) - { - mBirthList->setIndexSelected(index); - } - } -} - -void BirthDialog::updateSpells() -{ - for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSpellItems.clear(); - - if (mCurrentBirthId.empty()) - return; - - MWSpellPtr spellWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), 18); - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::BirthSign *birth = - store.get().find(mCurrentBirthId); - - std::string texturePath = std::string("textures\\") + birth->mTexture; - fixTexturePath(texturePath); - mBirthImage->setImageTexture(texturePath); - - std::vector abilities, powers, spells; - - std::vector::const_iterator it = birth->mPowers.mList.begin(); - std::vector::const_iterator end = birth->mPowers.mList.end(); - for (; it != end; ++it) - { - const std::string &spellId = *it; - const ESM::Spell *spell = store.get().search(spellId); - if (!spell) - continue; // Skip spells which cannot be found - ESM::Spell::SpellType type = static_cast(spell->mData.mType); - if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) - continue; // We only want spell, ability and powers. - - if (type == ESM::Spell::ST_Ability) - abilities.push_back(spellId); - else if (type == ESM::Spell::ST_Power) - powers.push_back(spellId); - else if (type == ESM::Spell::ST_Spell) - spells.push_back(spellId); - } - - int i = 0; - - struct { - const std::vector &spells; - const char *label; - } - categories[3] = { - {abilities, "sBirthsignmenu1"}, - {powers, "sPowers"}, - {spells, "sBirthsignmenu2"} - }; - - for (int category = 0; category < 3; ++category) - { - if (!categories[category].spells.empty()) - { - MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); - label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); - mSpellItems.push_back(label); - coord.top += lineHeight; - - std::vector::const_iterator end = categories[category].spells.end(); - for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) + if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) { - const std::string &spellId = *it; - spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); - spellWidget->setSpellId(spellId); + mBirthList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } + } - mSpellItems.push_back(spellWidget); - coord.top += lineHeight; + updateSpells(); + } - MyGUI::IntCoord spellCoord = coord; - spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template? - spellWidget->createEffectWidgets(mSpellItems, mSpellArea, spellCoord, (category == 0) ? MWEffectList::EF_Constant : 0); - coord.top = spellCoord.top; + // widget controls - ++i; + void BirthDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE) + return; + eventDone(this); + } + + void BirthDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) + { + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + const std::string *birthId = mBirthList->getItemDataAt(_index); + if (boost::iequals(mCurrentBirthId, *birthId)) + return; + + mCurrentBirthId = *birthId; + updateSpells(); + } + + // update widget content + + void BirthDialog::updateBirths() + { + mBirthList->removeAllItems(); + + const MWWorld::Store &signs = + MWBase::Environment::get().getWorld()->getStore().get(); + + // sort by name + std::vector < std::pair > birthSigns; + + MWWorld::Store::iterator it = signs.begin(); + for (; it != signs.end(); ++it) + { + birthSigns.push_back(std::make_pair(it->mId, &(*it))); + } + std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); + + int index = 0; + for (std::vector >::const_iterator it2 = birthSigns.begin(); + it2 != birthSigns.end(); ++it2, ++index) + { + mBirthList->addItem(it2->second->mName, it2->first); + if (mCurrentBirthId.empty()) + { + mBirthList->setIndexSelected(index); + mCurrentBirthId = it2->first; + } + else if (boost::iequals(it2->first, mCurrentBirthId)) + { + mBirthList->setIndexSelected(index); } } } + + void BirthDialog::updateSpells() + { + for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSpellItems.clear(); + + if (mCurrentBirthId.empty()) + return; + + Widgets::MWSpellPtr spellWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), 18); + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::BirthSign *birth = + store.get().find(mCurrentBirthId); + + std::string texturePath = std::string("textures\\") + birth->mTexture; + Widgets::fixTexturePath(texturePath); + mBirthImage->setImageTexture(texturePath); + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = birth->mPowers.mList.begin(); + std::vector::const_iterator end = birth->mPowers.mList.end(); + for (; it != end; ++it) + { + const std::string &spellId = *it; + const ESM::Spell *spell = store.get().search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->mData.mType); + if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) + continue; // We only want spell, ability and powers. + + if (type == ESM::Spell::ST_Ability) + abilities.push_back(spellId); + else if (type == ESM::Spell::ST_Power) + powers.push_back(spellId); + else if (type == ESM::Spell::ST_Spell) + spells.push_back(spellId); + } + + int i = 0; + + struct { + const std::vector &spells; + const char *label; + } + categories[3] = { + {abilities, "sBirthsignmenu1"}, + {powers, "sPowers"}, + {spells, "sBirthsignmenu2"} + }; + + for (int category = 0; category < 3; ++category) + { + if (!categories[category].spells.empty()) + { + MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); + label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); + mSpellItems.push_back(label); + coord.top += lineHeight; + + std::vector::const_iterator end = categories[category].spells.end(); + for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) + { + const std::string &spellId = *it; + spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); + spellWidget->setSpellId(spellId); + + mSpellItems.push_back(spellWidget); + coord.top += lineHeight; + + MyGUI::IntCoord spellCoord = coord; + spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template? + spellWidget->createEffectWidgets(mSpellItems, mSpellArea, spellCoord, (category == 0) ? Widgets::MWEffectList::EF_Constant : 0); + coord.top = spellCoord.top; + + ++i; + } + } + } + } + } diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ce74c4859..6d44e9d2c 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -12,148 +12,151 @@ #include "formatting.hpp" -using namespace MWGui; - -BookWindow::BookWindow () - : WindowBase("openmw_book.layout") - , mTakeButtonShow(true) - , mTakeButtonAllowed(true) +namespace MWGui { - getWidget(mCloseButton, "CloseButton"); - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); - getWidget(mTakeButton, "TakeButton"); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onTakeButtonClicked); - - getWidget(mNextPageButton, "NextPageBTN"); - mNextPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onNextPageButtonClicked); - - getWidget(mPrevPageButton, "PrevPageBTN"); - mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); - - getWidget(mLeftPageNumber, "LeftPageNumber"); - getWidget(mRightPageNumber, "RightPageNumber"); - - getWidget(mLeftPage, "LeftPage"); - getWidget(mRightPage, "RightPage"); - - center(); -} - -void BookWindow::clearPages() -{ - for (std::vector::iterator it=mPages.begin(); - it!=mPages.end(); ++it) + BookWindow::BookWindow () + : WindowBase("openmw_book.layout") + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mPages.clear(); -} + getWidget(mCloseButton, "CloseButton"); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); -void BookWindow::open (MWWorld::Ptr book) -{ - mBook = book; + getWidget(mTakeButton, "TakeButton"); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onTakeButtonClicked); - clearPages(); - mCurrentPage = 0; + getWidget(mNextPageButton, "NextPageBTN"); + mNextPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onNextPageButtonClicked); - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + getWidget(mPrevPageButton, "PrevPageBTN"); + mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); - MWWorld::LiveCellRef *ref = mBook.get(); + getWidget(mLeftPageNumber, "LeftPageNumber"); + getWidget(mRightPageNumber, "RightPageNumber"); - BookTextParser parser; - std::vector results = parser.split(ref->mBase->mText, mLeftPage->getSize().width, mLeftPage->getSize().height); + getWidget(mLeftPage, "LeftPage"); + getWidget(mRightPage, "RightPage"); - int i=0; - for (std::vector::iterator it=results.begin(); - it!=results.end(); ++it) - { - MyGUI::Widget* parent; - if (i%2 == 0) - parent = mLeftPage; - else - parent = mRightPage; - - MyGUI::Widget* pageWidget = parent->createWidgetReal("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast(i)); - parser.parse(*it, pageWidget, mLeftPage->getSize().width); - mPages.push_back(pageWidget); - ++i; + center(); } - updatePages(); - - setTakeButtonShow(true); -} - -void BookWindow::setTakeButtonShow(bool show) -{ - mTakeButtonShow = show; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void BookWindow::setInventoryAllowed(bool allowed) -{ - mTakeButtonAllowed = allowed; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) -{ - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); -} - -void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); - - MWWorld::ActionTake take(mBook); - take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); -} - -void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) -{ - if ((mCurrentPage+1)*2 < mPages.size()) + void BookWindow::clearPages() { - MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); - - ++mCurrentPage; - - updatePages(); - } -} - -void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender) -{ - if (mCurrentPage > 0) - { - MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); - - --mCurrentPage; - - updatePages(); - } -} - -void BookWindow::updatePages() -{ - mLeftPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 1) ); - mRightPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 2) ); - - unsigned int i=0; - for (std::vector::iterator it = mPages.begin(); - it != mPages.end(); ++it) - { - if (mCurrentPage*2 == i || mCurrentPage*2+1 == i) - (*it)->setVisible(true); - else + for (std::vector::iterator it=mPages.begin(); + it!=mPages.end(); ++it) { - (*it)->setVisible(false); + MyGUI::Gui::getInstance().destroyWidget(*it); } - ++i; + mPages.clear(); } + + void BookWindow::open (MWWorld::Ptr book) + { + mBook = book; + + clearPages(); + mCurrentPage = 0; + + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + + MWWorld::LiveCellRef *ref = mBook.get(); + + BookTextParser parser; + std::vector results = parser.split(ref->mBase->mText, mLeftPage->getSize().width, mLeftPage->getSize().height); + + int i=0; + for (std::vector::iterator it=results.begin(); + it!=results.end(); ++it) + { + MyGUI::Widget* parent; + if (i%2 == 0) + parent = mLeftPage; + else + parent = mRightPage; + + MyGUI::Widget* pageWidget = parent->createWidgetReal("", MyGUI::FloatCoord(0.0,0.0,1.0,1.0), MyGUI::Align::Default, "BookPage" + boost::lexical_cast(i)); + parser.parse(*it, pageWidget, mLeftPage->getSize().width); + mPages.push_back(pageWidget); + ++i; + } + + updatePages(); + + setTakeButtonShow(true); + } + + void BookWindow::setTakeButtonShow(bool show) + { + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void BookWindow::setInventoryAllowed(bool allowed) + { + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void BookWindow::onCloseButtonClicked (MyGUI::Widget* sender) + { + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); + } + + void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); + + MWWorld::ActionTake take(mBook); + take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); + } + + void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) + { + if ((mCurrentPage+1)*2 < mPages.size()) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); + + ++mCurrentPage; + + updatePages(); + } + } + + void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender) + { + if (mCurrentPage > 0) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); + + --mCurrentPage; + + updatePages(); + } + } + + void BookWindow::updatePages() + { + mLeftPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 1) ); + mRightPageNumber->setCaption( boost::lexical_cast(mCurrentPage*2 + 2) ); + + unsigned int i=0; + for (std::vector::iterator it = mPages.begin(); + it != mPages.end(); ++it) + { + if (mCurrentPage*2 == i || mCurrentPage*2+1 == i) + (*it)->setVisible(true); + else + { + (*it)->setVisible(false); + } + ++i; + } + } + } diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 28f6d13ee..fc8c24484 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -43,682 +43,685 @@ namespace }; } -using namespace MWGui; - -CharacterCreation::CharacterCreation() - : mNameDialog(0) - , mRaceDialog(0) - , mClassChoiceDialog(0) - , mGenerateClassQuestionDialog(0) - , mGenerateClassResultDialog(0) - , mPickClassDialog(0) - , mCreateClassDialog(0) - , mBirthSignDialog(0) - , mReviewDialog(0) - , mGenerateClassStep(0) +namespace MWGui { - mCreationStage = CSE_NotStarted; -} -void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - if (mReviewDialog) + CharacterCreation::CharacterCreation() + : mNameDialog(0) + , mRaceDialog(0) + , mClassChoiceDialog(0) + , mGenerateClassQuestionDialog(0) + , mGenerateClassResultDialog(0) + , mPickClassDialog(0) + , mCreateClassDialog(0) + , mBirthSignDialog(0) + , mReviewDialog(0) + , mGenerateClassStep(0) { - static const char *ids[] = + mCreationStage = CSE_NotStarted; + } + + void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat& value) + { + if (mReviewDialog) { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) + mReviewDialog->setAttribute(ESM::Attribute::AttributeID(i), value); + } + } + } + + void CharacterCreation::setValue (const std::string& id, const MWMechanics::DynamicStat& value) + { + if (mReviewDialog) + { + if (id == "HBar") + { + mReviewDialog->setHealth (value); + } + else if (id == "MBar") + { + mReviewDialog->setMagicka (value); + } + else if (id == "FBar") + { + mReviewDialog->setFatigue (value); + } + } + } + + void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) + { + if (mReviewDialog) + mReviewDialog->setSkillValue(parSkill, value); + } + + void CharacterCreation::configureSkills (const SkillList& major, const SkillList& minor) + { + if (mReviewDialog) + mReviewDialog->configureSkills(major, minor); + } + + void CharacterCreation::spawnDialog(const char id) + { + switch (id) + { + case GM_Name: + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); + mNameDialog->setTextInput(mPlayerName); + mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); + mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); + mNameDialog->setVisible(true); + break; + + case GM_Race: + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + mRaceDialog = new RaceDialog(); + mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); + mRaceDialog->setRaceId(mPlayerRaceId); + mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); + mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); + mRaceDialog->setVisible(true); + if (mCreationStage < CSE_NameChosen) + mCreationStage = CSE_NameChosen; + break; + + case GM_Class: + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + mClassChoiceDialog = new ClassChoiceDialog(); + mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); + mClassChoiceDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + + case GM_ClassPick: + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + mPickClassDialog = new PickClassDialog(); + mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mPickClassDialog->setClassId(mPlayerClass.mName); + mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); + mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); + mPickClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + + case GM_Birth: + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + mBirthSignDialog = new BirthDialog(); + mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); + mBirthSignDialog->setBirthId(mPlayerBirthSignId); + mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); + mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); + mBirthSignDialog->setVisible(true); + if (mCreationStage < CSE_ClassChosen) + mCreationStage = CSE_ClassChosen; + break; + + case GM_ClassCreate: + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); + mCreateClassDialog = 0; + mCreateClassDialog = new CreateClassDialog(); + mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); + mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); + mCreateClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_ClassGenerate: + mGenerateClassStep = 0; + mGenerateClass = ""; + mGenerateClassSpecializations[0] = 0; + mGenerateClassSpecializations[1] = 0; + mGenerateClassSpecializations[2] = 0; + showClassQuestionDialog(); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_Review: + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mReviewDialog = new ReviewDialog(); + mReviewDialog->setPlayerName(mPlayerName); + mReviewDialog->setRace(mPlayerRaceId); + mReviewDialog->setClass(mPlayerClass); + mReviewDialog->setBirthSign(mPlayerBirthSignId); + + mReviewDialog->setHealth(mPlayerHealth); + mReviewDialog->setMagicka(mPlayerMagicka); + mReviewDialog->setFatigue(mPlayerFatigue); + + { + std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); + for (std::map >::iterator it = attributes.begin(); + it != attributes.end(); ++it) + { + mReviewDialog->setAttribute(static_cast (it->first), it->second); + } + } + + { + std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); + for (std::map >::iterator it = skills.begin(); + it != skills.end(); ++it) + { + mReviewDialog->setSkillValue(static_cast (it->first), it->second); + } + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); + } + + mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); + mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); + mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); + mReviewDialog->setVisible(true); + if (mCreationStage < CSE_BirthSignChosen) + mCreationStage = CSE_BirthSignChosen; + break; + } + } + + void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) + { + mPlayerHealth = value; + } + + void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat& value) + { + mPlayerMagicka = value; + } + + void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& value) + { + mPlayerFatigue = value; + } + + void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + + void CharacterCreation::onReviewDialogBack() + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + + void CharacterCreation::onReviewActivateDialog(int parDialog) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mCreationStage = CSE_ReviewNext; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + switch(parDialog) + { + case ReviewDialog::NAME_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); + break; + case ReviewDialog::RACE_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + break; + case ReviewDialog::CLASS_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + break; + case ReviewDialog::BIRTHSIGN_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); }; - - for (int i=0; ids[i]; ++i) - { - if (ids[i]==id) - mReviewDialog->setAttribute(ESM::Attribute::AttributeID(i), value); - } } -} -void CharacterCreation::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - if (mReviewDialog) + void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) { - if (id == "HBar") + if (mPickClassDialog) { - mReviewDialog->setHealth (value); - } - else if (id == "MBar") - { - mReviewDialog->setMagicka (value); - } - else if (id == "FBar") - { - mReviewDialog->setFatigue (value); - } - } -} + const std::string &classId = mPickClassDialog->getClassId(); + if (!classId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); -void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) -{ - if (mReviewDialog) - mReviewDialog->setSkillValue(parSkill, value); -} - -void CharacterCreation::configureSkills (const SkillList& major, const SkillList& minor) -{ - if (mReviewDialog) - mReviewDialog->configureSkills(major, minor); -} - -void CharacterCreation::spawnDialog(const char id) -{ - switch (id) - { - case GM_Name: - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - mNameDialog = new TextInputDialog(); - mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); - mNameDialog->setTextInput(mPlayerName); - mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); - mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); - mNameDialog->setVisible(true); - break; - - case GM_Race: - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - mRaceDialog = new RaceDialog(); - mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); - mRaceDialog->setRaceId(mPlayerRaceId); - mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); - mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); - mRaceDialog->setVisible(true); - if (mCreationStage < CSE_NameChosen) - mCreationStage = CSE_NameChosen; - break; - - case GM_Class: - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(); - mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); - mClassChoiceDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - - case GM_ClassPick: + const ESM::Class *klass = + MWBase::Environment::get().getWorld()->getStore().get().find(classId); + if (klass) + { + mPlayerClass = *klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + } MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(); - mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mPickClassDialog->setClassId(mPlayerClass.mName); - mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); - mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); - mPickClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + } - case GM_Birth: + //TODO This bit gets repeated a few times; wrap it in a function + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + else + { + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onPickClassDialogBack() + { + if (mPickClassDialog) + { + const std::string classId = mPickClassDialog->getClassId(); + if (!classId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onClassChoice(int _index) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + switch(_index) + { + case ClassChoiceDialog::Class_Generate: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); + break; + case ClassChoiceDialog::Class_Pick: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); + break; + case ClassChoiceDialog::Class_Create: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); + break; + case ClassChoiceDialog::Class_Back: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + break; + + }; + } + + void CharacterCreation::onNameDialogDone(WindowBase* parWindow) + { + if (mNameDialog) + { + mPlayerName = mNameDialog->getTextInput(); + MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); + MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + } + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_NameChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + } + else + { + mCreationStage = CSE_NameChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onRaceDialogBack() + { + if (mRaceDialog) + { + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); + } + + void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) + { + if (mRaceDialog) + { + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); + + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + } + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_RaceChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + else + { + mCreationStage = CSE_RaceChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + { + if (mBirthSignDialog) + { + mPlayerBirthSignId = mBirthSignDialog->getBirthId(); + if (!mPlayerBirthSignId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(); - mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); - mBirthSignDialog->setBirthId(mPlayerBirthSignId); - mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); - mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); - mBirthSignDialog->setVisible(true); - if (mCreationStage < CSE_ClassChosen) - mCreationStage = CSE_ClassChosen; - break; + } + + if (mCreationStage >= CSE_BirthSignChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else + { + mCreationStage = CSE_BirthSignChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onBirthSignDialogBack() + { + if (mBirthSignDialog) + { + MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + { + if (mCreateClassDialog) + { + ESM::Class klass; + klass.mName = mCreateClassDialog->getName(); + klass.mDescription = mCreateClassDialog->getDescription(); + klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); + klass.mData.mIsPlayable = 0x1; + + std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); + assert(attributes.size() == 2); + klass.mData.mAttribute[0] = attributes[0]; + klass.mData.mAttribute[1] = attributes[1]; + + std::vector majorSkills = mCreateClassDialog->getMajorSkills(); + std::vector minorSkills = mCreateClassDialog->getMinorSkills(); + assert(majorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); + assert(minorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); + for (size_t i = 0; i < sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0]); ++i) + { + klass.mData.mSkills[i][1] = majorSkills[i]; + klass.mData.mSkills[i][0] = minorSkills[i]; + } + + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); + mPlayerClass = klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - case GM_ClassCreate: MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mCreateClassDialog = new CreateClassDialog(); - mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); - mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); - mCreateClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_ClassGenerate: - mGenerateClassStep = 0; - mGenerateClass = ""; - mGenerateClassSpecializations[0] = 0; - mGenerateClassSpecializations[1] = 0; - mGenerateClassSpecializations[2] = 0; - showClassQuestionDialog(); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_Review: - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mReviewDialog = new ReviewDialog(); - mReviewDialog->setPlayerName(mPlayerName); - mReviewDialog->setRace(mPlayerRaceId); - mReviewDialog->setClass(mPlayerClass); - mReviewDialog->setBirthSign(mPlayerBirthSignId); + } - mReviewDialog->setHealth(mPlayerHealth); - mReviewDialog->setMagicka(mPlayerMagicka); - mReviewDialog->setFatigue(mPlayerFatigue); - - { - std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map >::iterator it = attributes.begin(); - it != attributes.end(); ++it) - { - mReviewDialog->setAttribute(static_cast (it->first), it->second); - } - } - - { - std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map >::iterator it = skills.begin(); - it != skills.end(); ++it) - { - mReviewDialog->setSkillValue(static_cast (it->first), it->second); - } - mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); - } - - mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); - mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); - mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); - mReviewDialog->setVisible(true); - if (mCreationStage < CSE_BirthSignChosen) - mCreationStage = CSE_BirthSignChosen; - break; - } -} - -void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) -{ - mPlayerHealth = value; -} - -void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat& value) -{ - mPlayerMagicka = value; -} - -void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& value) -{ - mPlayerFatigue = value; -} - -void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); -} - -void CharacterCreation::onReviewDialogBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); -} - -void CharacterCreation::onReviewActivateDialog(int parDialog) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mCreationStage = CSE_ReviewNext; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - - switch(parDialog) - { - case ReviewDialog::NAME_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); - break; - case ReviewDialog::RACE_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - break; - case ReviewDialog::CLASS_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - break; - case ReviewDialog::BIRTHSIGN_DIALOG: + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - }; -} - -void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) -{ - if (mPickClassDialog) - { - const std::string &classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - - const ESM::Class *klass = - MWBase::Environment::get().getWorld()->getStore().get().find(classId); - if (klass) + } + else { - mPlayerClass = *klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); } - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; } - //TODO This bit gets repeated a few times; wrap it in a function - if (mCreationStage == CSE_ReviewNext) + void CharacterCreation::onCreateClassDialogBack() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onPickClassDialogBack() -{ - if (mPickClassDialog) - { - const std::string classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onClassChoice(int _index) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - - switch(_index) - { - case ClassChoiceDialog::Class_Generate: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); - break; - case ClassChoiceDialog::Class_Pick: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); - break; - case ClassChoiceDialog::Class_Create: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); - break; - case ClassChoiceDialog::Class_Back: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - break; - - }; -} - -void CharacterCreation::onNameDialogDone(WindowBase* parWindow) -{ - if (mNameDialog) - { - mPlayerName = mNameDialog->getTextInput(); - MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); - MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - } - - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_NameChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - } - else - { - mCreationStage = CSE_NameChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onRaceDialogBack() -{ - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); -} - -void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) -{ - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); - - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_RaceChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - else - { - mCreationStage = CSE_RaceChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) -{ - if (mBirthSignDialog) - { - mPlayerBirthSignId = mBirthSignDialog->getBirthId(); - if (!mPlayerBirthSignId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } - - if (mCreationStage >= CSE_BirthSignChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else - { - mCreationStage = CSE_BirthSignChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onBirthSignDialogBack() -{ - if (mBirthSignDialog) - { - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) -{ - if (mCreateClassDialog) - { - ESM::Class klass; - klass.mName = mCreateClassDialog->getName(); - klass.mDescription = mCreateClassDialog->getDescription(); - klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); - klass.mData.mIsPlayable = 0x1; - - std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); - assert(attributes.size() == 2); - klass.mData.mAttribute[0] = attributes[0]; - klass.mData.mAttribute[1] = attributes[1]; - - std::vector majorSkills = mCreateClassDialog->getMajorSkills(); - std::vector minorSkills = mCreateClassDialog->getMinorSkills(); - assert(majorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); - assert(minorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); - for (size_t i = 0; i < sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0]); ++i) - { - klass.mData.mSkills[i][1] = majorSkills[i]; - klass.mData.mSkills[i][0] = minorSkills[i]; - } - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); - mPlayerClass = klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - } - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onCreateClassDialogBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); - mCreateClassDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onClassQuestionChosen(int _index) -{ - MWBase::Environment::get().getSoundManager()->stopSay(); - - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); - mGenerateClassQuestionDialog = 0; - - if (_index < 0 || _index >= 3) - { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - return; } - ESM::Class::Specialization specialization = mSpecializations[_index]; - if (specialization == ESM::Class::Stealth) - ++mGenerateClassSpecializations[0]; - else if (specialization == ESM::Class::Combat) - ++mGenerateClassSpecializations[1]; - else if (specialization == ESM::Class::Magic) - ++mGenerateClassSpecializations[2]; - ++mGenerateClassStep; - showClassQuestionDialog(); -} - -void CharacterCreation::showClassQuestionDialog() -{ - if (mGenerateClassStep == 10) + void CharacterCreation::onClassQuestionChosen(int _index) { - static boost::array classes = { { - {"Acrobat", {6, 2, 2}}, - {"Agent", {6, 1, 3}}, - {"Archer", {3, 5, 2}}, - {"Archer", {5, 5, 0}}, - {"Assassin", {6, 3, 1}}, - {"Barbarian", {3, 6, 1}}, - {"Bard", {3, 3, 3}}, - {"Battlemage", {1, 3, 6}}, - {"Crusader", {1, 6, 3}}, - {"Healer", {3, 1, 6}}, - {"Knight", {2, 6, 2}}, - {"Monk", {5, 3, 2}}, - {"Nightblade", {4, 2, 4}}, - {"Pilgrim", {5, 2, 3}}, - {"Rogue", {3, 4, 3}}, - {"Rogue", {4, 4, 2}}, - {"Rogue", {5, 4, 1}}, - {"Scout", {2, 5, 3}}, - {"Sorcerer", {2, 2, 6}}, - {"Spellsword", {2, 4, 4}}, - {"Spellsword", {5, 1, 4}}, - {"Witchhunter", {2, 3, 5}}, - {"Witchhunter", {5, 0, 5}} - } }; + MWBase::Environment::get().getSoundManager()->stopSay(); - int match = -1; - for (unsigned i = 0; i < classes.size(); ++i) + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); + mGenerateClassQuestionDialog = 0; + + if (_index < 0 || _index >= 3) { - if (mGenerateClassSpecializations[0] == classes[i].points[0] && - mGenerateClassSpecializations[1] == classes[i].points[1] && - mGenerateClassSpecializations[2] == classes[i].points[2]) - { - match = i; - mGenerateClass = classes[i].id; - break; - } + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + return; } - if (match == -1) + ESM::Class::Specialization specialization = mSpecializations[_index]; + if (specialization == ESM::Class::Stealth) + ++mGenerateClassSpecializations[0]; + else if (specialization == ESM::Class::Combat) + ++mGenerateClassSpecializations[1]; + else if (specialization == ESM::Class::Magic) + ++mGenerateClassSpecializations[2]; + ++mGenerateClassStep; + showClassQuestionDialog(); + } + + void CharacterCreation::showClassQuestionDialog() + { + if (mGenerateClassStep == 10) { - if (mGenerateClassSpecializations[0] >= 7) - mGenerateClass = "Thief"; - else if (mGenerateClassSpecializations[1] >= 7) - mGenerateClass = "Warrior"; - else if (mGenerateClassSpecializations[2] >= 7) - mGenerateClass = "Mage"; - else + static boost::array classes = { { + {"Acrobat", {6, 2, 2}}, + {"Agent", {6, 1, 3}}, + {"Archer", {3, 5, 2}}, + {"Archer", {5, 5, 0}}, + {"Assassin", {6, 3, 1}}, + {"Barbarian", {3, 6, 1}}, + {"Bard", {3, 3, 3}}, + {"Battlemage", {1, 3, 6}}, + {"Crusader", {1, 6, 3}}, + {"Healer", {3, 1, 6}}, + {"Knight", {2, 6, 2}}, + {"Monk", {5, 3, 2}}, + {"Nightblade", {4, 2, 4}}, + {"Pilgrim", {5, 2, 3}}, + {"Rogue", {3, 4, 3}}, + {"Rogue", {4, 4, 2}}, + {"Rogue", {5, 4, 1}}, + {"Scout", {2, 5, 3}}, + {"Sorcerer", {2, 2, 6}}, + {"Spellsword", {2, 4, 4}}, + {"Spellsword", {5, 1, 4}}, + {"Witchhunter", {2, 3, 5}}, + {"Witchhunter", {5, 0, 5}} + } }; + + int match = -1; + for (unsigned i = 0; i < classes.size(); ++i) { - std::cerr << "Failed to deduce class from chosen answers in generate class dialog" << std::endl; - mGenerateClass = "Thief"; + if (mGenerateClassSpecializations[0] == classes[i].points[0] && + mGenerateClassSpecializations[1] == classes[i].points[1] && + mGenerateClassSpecializations[2] == classes[i].points[2]) + { + match = i; + mGenerateClass = classes[i].id; + break; + } } + + if (match == -1) + { + if (mGenerateClassSpecializations[0] >= 7) + mGenerateClass = "Thief"; + else if (mGenerateClassSpecializations[1] >= 7) + mGenerateClass = "Warrior"; + else if (mGenerateClassSpecializations[2] >= 7) + mGenerateClass = "Mage"; + else + { + std::cerr << "Failed to deduce class from chosen answers in generate class dialog" << std::endl; + mGenerateClass = "Thief"; + } + } + + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + + mGenerateClassResultDialog = new GenerateClassResultDialog(); + mGenerateClassResultDialog->setClassId(mGenerateClass); + mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); + mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); + mGenerateClassResultDialog->setVisible(true); + return; } + if (mGenerateClassStep > 10) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + return; + } + + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); + mGenerateClassQuestionDialog = 0; + + mGenerateClassQuestionDialog = new InfoBoxDialog(); + + InfoBoxDialog::ButtonList buttons; + mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[0]); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[1]); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[2]); + mGenerateClassQuestionDialog->setButtons(buttons); + mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); + mGenerateClassQuestionDialog->setVisible(true); + + MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); + } + + void CharacterCreation::onGenerateClassBack() + { MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; - mGenerateClassResultDialog = new GenerateClassResultDialog(); - mGenerateClassResultDialog->setClassId(mGenerateClass); - mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); - mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); - mGenerateClassResultDialog->setVisible(true); - return; - } + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - if (mGenerateClassStep > 10) - { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - return; } - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); - mGenerateClassQuestionDialog = 0; - - mGenerateClassQuestionDialog = new InfoBoxDialog(); - - InfoBoxDialog::ButtonList buttons; - mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[0]); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[1]); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[2]); - mGenerateClassQuestionDialog->setButtons(buttons); - mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); - mGenerateClassQuestionDialog->setVisible(true); - - MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); -} - -void CharacterCreation::onGenerateClassBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - const ESM::Class *klass = - MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); - - mPlayerClass = *klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); - - if (mCreationStage == CSE_ReviewNext) + void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); + + const ESM::Class *klass = + MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); + + mPlayerClass = *klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + else + { + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + CharacterCreation::~CharacterCreation() + { + delete mNameDialog; + delete mRaceDialog; + delete mClassChoiceDialog; + delete mGenerateClassQuestionDialog; + delete mGenerateClassResultDialog; + delete mPickClassDialog; + delete mCreateClassDialog; + delete mBirthSignDialog; + delete mReviewDialog; + } -CharacterCreation::~CharacterCreation() -{ - delete mNameDialog; - delete mRaceDialog; - delete mClassChoiceDialog; - delete mGenerateClassQuestionDialog; - delete mGenerateClassResultDialog; - delete mPickClassDialog; - delete mCreateClassDialog; - delete mBirthSignDialog; - delete mReviewDialog; } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e4d32c933..ab8103868 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -11,870 +11,873 @@ #undef min #undef max -using namespace MWGui; - -/* GenerateClassResultDialog */ - -GenerateClassResultDialog::GenerateClassResultDialog() - : WindowModal("openmw_chargen_generate_class_result.layout") +namespace MWGui { - // Centre dialog - center(); - setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); + /* GenerateClassResultDialog */ - getWidget(mClassImage, "ClassImage"); - getWidget(mClassName, "ClassName"); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); -} - -std::string GenerateClassResultDialog::getClassId() const -{ - return mClassName->getCaption(); -} - -void GenerateClassResultDialog::setClassId(const std::string &classId) -{ - mCurrentClassId = classId; - mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); - mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().get().find(mCurrentClassId)->mName); -} - -// widget controls - -void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); -} - -void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -/* PickClassDialog */ - -PickClassDialog::PickClassDialog() - : WindowModal("openmw_chargen_class.layout") -{ - // Centre dialog - center(); - - getWidget(mSpecializationName, "SpecializationName"); - - getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); - getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); - - for(int i = 0; i < 5; i++) + GenerateClassResultDialog::GenerateClassResultDialog() + : WindowModal("openmw_chargen_generate_class_result.layout") { - char theIndex = '0'+i; - getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); - getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - } + // Centre dialog + center(); - getWidget(mClassList, "ClassList"); - mClassList->setScrollVisible(true); - mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); - getWidget(mClassImage, "ClassImage"); + getWidget(mClassImage, "ClassImage"); + getWidget(mClassName, "ClassName"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); - - updateClasses(); - updateStats(); -} - -void PickClassDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); + } -void PickClassDialog::open() -{ - WindowModal::open (); - updateClasses(); - updateStats(); -} - - -void PickClassDialog::setClassId(const std::string &classId) -{ - mCurrentClassId = classId; - mClassList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mClassList->getItemCount(); - for (size_t i = 0; i < count; ++i) + std::string GenerateClassResultDialog::getClassId() const { - if (boost::iequals(*mClassList->getItemDataAt(i), classId)) + return mClassName->getCaption(); + } + + void GenerateClassResultDialog::setClassId(const std::string &classId) + { + mCurrentClassId = classId; + mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); + mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().get().find(mCurrentClassId)->mName); + } + + // widget controls + + void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); + } + + void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + /* PickClassDialog */ + + PickClassDialog::PickClassDialog() + : WindowModal("openmw_chargen_class.layout") + { + // Centre dialog + center(); + + getWidget(mSpecializationName, "SpecializationName"); + + getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); + getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); + + for(int i = 0; i < 5; i++) { - mClassList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; + char theIndex = '0'+i; + getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); + getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); } + + getWidget(mClassList, "ClassList"); + mClassList->setScrollVisible(true); + mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + + getWidget(mClassImage, "ClassImage"); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); + + updateClasses(); + updateStats(); } - updateStats(); -} - -// widget controls - -void PickClassDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void PickClassDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - const std::string *classId = mClassList->getItemDataAt(_index); - if (boost::iequals(mCurrentClassId, *classId)) - return; - - mCurrentClassId = *classId; - updateStats(); -} - -// update widget content - -void PickClassDialog::updateClasses() -{ - mClassList->removeAllItems(); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - - int index = 0; - MWWorld::Store::iterator it = store.get().begin(); - for (; it != store.get().end(); ++it) + void PickClassDialog::setNextButtonShow(bool shown) { - bool playable = (it->mData.mIsPlayable != 0); - if (!playable) // Only display playable classes - continue; + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); - const std::string &id = it->mId; - mClassList->addItem(it->mName, id); - if (mCurrentClassId.empty()) + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void PickClassDialog::open() + { + WindowModal::open (); + updateClasses(); + updateStats(); + } + + + void PickClassDialog::setClassId(const std::string &classId) + { + mCurrentClassId = classId; + mClassList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mClassList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mCurrentClassId = id; - mClassList->setIndexSelected(index); + if (boost::iequals(*mClassList->getItemDataAt(i), classId)) + { + mClassList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } } - else if (boost::iequals(id, mCurrentClassId)) - { - mClassList->setIndexSelected(index); - } - ++index; - } -} -void PickClassDialog::updateStats() -{ - if (mCurrentClassId.empty()) - return; - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Class *klass = store.get().search(mCurrentClassId); - if (!klass) - return; - - ESM::Class::Specialization specialization = static_cast(klass->mData.mSpecialization); - - static const char *specIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" - }; - std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); - mSpecializationName->setCaption(specName); - ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); - - mFavoriteAttribute[0]->setAttributeId(klass->mData.mAttribute[0]); - mFavoriteAttribute[1]->setAttributeId(klass->mData.mAttribute[1]); - ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); - ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); - - for (int i = 0; i < 5; ++i) - { - mMinorSkill[i]->setSkillNumber(klass->mData.mSkills[i][0]); - mMajorSkill[i]->setSkillNumber(klass->mData.mSkills[i][1]); - ToolTips::createSkillToolTip(mMinorSkill[i], klass->mData.mSkills[i][0]); - ToolTips::createSkillToolTip(mMajorSkill[i], klass->mData.mSkills[i][1]); + updateStats(); } - mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); -} + // widget controls -/* InfoBoxDialog */ - -void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) -{ - MyGUI::IntCoord inner = widget->getTextRegion(); - MyGUI::IntCoord outer = widget->getCoord(); - MyGUI::IntSize size = widget->getTextSize(); - size.width += outer.width - inner.width; - size.height += outer.height - inner.height; - widget->setSize(size); -} - -void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) -{ - size_t count = widget->getChildCount(); - int pos = 0; - pos += margin; - int width = 0; - for (unsigned i = 0; i < count; ++i) + void PickClassDialog::onOkClicked(MyGUI::Widget* _sender) { - MyGUI::Widget* child = widget->getChildAt(i); - if (!child->getVisible()) - continue; - - child->setPosition(child->getLeft(), pos); - width = std::max(width, child->getWidth()); - pos += child->getHeight() + margin; - } - width += margin*2; - widget->setSize(width, pos); -} - -InfoBoxDialog::InfoBoxDialog() - : WindowModal("openmw_infobox.layout") - , mCurrentButton(-1) -{ - getWidget(mTextBox, "TextBox"); - getWidget(mText, "Text"); - mText->getSubWidgetText()->setWordWrap(true); - getWidget(mButtonBar, "ButtonBar"); - - center(); -} - -void InfoBoxDialog::setText(const std::string &str) -{ - mText->setCaption(str); - mTextBox->setVisible(!str.empty()); - fitToText(mText); -} - -std::string InfoBoxDialog::getText() const -{ - return mText->getCaption(); -} - -void InfoBoxDialog::setButtons(ButtonList &buttons) -{ - for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - this->mButtons.clear(); - mCurrentButton = -1; - - // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget - MyGUI::Button* button; - MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); - ButtonList::const_iterator end = buttons.end(); - for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) - { - const std::string &text = *it; - button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); - button->getSubWidgetText()->setWordWrap(true); - button->setCaption(text); - fitToText(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); - coord.top += button->getHeight(); - this->mButtons.push_back(button); - } -} - -void InfoBoxDialog::open() -{ - WindowModal::open(); - // Fix layout - layoutVertically(mTextBox, 4); - layoutVertically(mButtonBar, 6); - layoutVertically(mMainWidget, 4 + 6); - - center(); -} - -int InfoBoxDialog::getChosenButton() const -{ - return mCurrentButton; -} - -void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) -{ - std::vector::const_iterator end = mButtons.end(); - int i = 0; - for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) - { - if (*it == _sender) - { - mCurrentButton = i; - eventButtonSelected(i); + if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE) return; - } - ++i; - } -} - -/* ClassChoiceDialog */ - -ClassChoiceDialog::ClassChoiceDialog() - : InfoBoxDialog() -{ - setText(""); - ButtonList buttons; - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); - setButtons(buttons); -} - -/* CreateClassDialog */ - -CreateClassDialog::CreateClassDialog() - : WindowModal("openmw_chargen_create_class.layout") - , mSpecDialog(NULL) - , mAttribDialog(NULL) - , mSkillDialog(NULL) - , mDescDialog(NULL) -{ - // Centre dialog - center(); - - setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); - getWidget(mSpecializationName, "SpecializationName"); - mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); - - setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); - getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); - getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); - mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - - setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); - setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); - for(int i = 0; i < 5; i++) - { - char theIndex = '0'+i; - getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); - getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - mSkills.push_back(mMajorSkill[i]); - mSkills.push_back(mMinorSkill[i]); + eventDone(this); } - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + void PickClassDialog::onBackClicked(MyGUI::Widget* _sender) { - (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + eventBack(); } - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); - getWidget(mEditName, "EditName"); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); - - MyGUI::Button* descriptionButton; - getWidget(descriptionButton, "DescriptionButton"); - descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); - - // Set default skills, attributes - - mFavoriteAttribute0->setAttributeId(ESM::Attribute::Strength); - mFavoriteAttribute1->setAttributeId(ESM::Attribute::Agility); - - mMajorSkill[0]->setSkillId(ESM::Skill::Block); - mMajorSkill[1]->setSkillId(ESM::Skill::Armorer); - mMajorSkill[2]->setSkillId(ESM::Skill::MediumArmor); - mMajorSkill[3]->setSkillId(ESM::Skill::HeavyArmor); - mMajorSkill[4]->setSkillId(ESM::Skill::BluntWeapon); - - mMinorSkill[0]->setSkillId(ESM::Skill::LongBlade); - mMinorSkill[1]->setSkillId(ESM::Skill::Axe); - mMinorSkill[2]->setSkillId(ESM::Skill::Spear); - mMinorSkill[3]->setSkillId(ESM::Skill::Athletics); - mMinorSkill[4]->setSkillId(ESM::Skill::Enchant); - - setSpecialization(0); - update(); -} - -CreateClassDialog::~CreateClassDialog() -{ - delete mSpecDialog; - delete mAttribDialog; - delete mSkillDialog; - delete mDescDialog; -} - -void CreateClassDialog::update() -{ - for (int i = 0; i < 5; ++i) + void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) { - ToolTips::createSkillToolTip(mMajorSkill[i], mMajorSkill[i]->getSkillId()); - ToolTips::createSkillToolTip(mMinorSkill[i], mMinorSkill[i]->getSkillId()); + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + const std::string *classId = mClassList->getItemDataAt(_index); + if (boost::iequals(mCurrentClassId, *classId)) + return; + + mCurrentClassId = *classId; + updateStats(); } - ToolTips::createAttributeToolTip(mFavoriteAttribute0, mFavoriteAttribute0->getAttributeId()); - ToolTips::createAttributeToolTip(mFavoriteAttribute1, mFavoriteAttribute1->getAttributeId()); -} + // update widget content -std::string CreateClassDialog::getName() const -{ - return mEditName->getOnlyText(); -} - -std::string CreateClassDialog::getDescription() const -{ - return mDescription; -} - -ESM::Class::Specialization CreateClassDialog::getSpecializationId() const -{ - return mSpecializationId; -} - -std::vector CreateClassDialog::getFavoriteAttributes() const -{ - std::vector v; - v.push_back(mFavoriteAttribute0->getAttributeId()); - v.push_back(mFavoriteAttribute1->getAttributeId()); - return v; -} - -std::vector CreateClassDialog::getMajorSkills() const -{ - std::vector v; - for(int i = 0; i < 5; i++) + void PickClassDialog::updateClasses() { - v.push_back(mMajorSkill[i]->getSkillId()); - } - return v; -} + mClassList->removeAllItems(); -std::vector CreateClassDialog::getMinorSkills() const -{ - std::vector v; - for(int i=0; i < 5; i++) - { - v.push_back(mMinorSkill[i]->getSkillId()); - } - return v; -} + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); -void CreateClassDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -// widget controls - -void CreateClassDialog::onDialogCancel() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); - mSpecDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); - mAttribDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); - mSkillDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); - mDescDialog = 0; -} - -void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) -{ - delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(); - mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); - mSpecDialog->setVisible(true); -} - -void CreateClassDialog::onSpecializationSelected() -{ - mSpecializationId = mSpecDialog->getSpecializationId(); - setSpecialization(mSpecializationId); - - MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); - mSpecDialog = 0; -} - -void CreateClassDialog::setSpecialization(int id) -{ - mSpecializationId = (ESM::Class::Specialization) id; - static const char *specIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" - }; - std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); - mSpecializationName->setCaption(specName); - ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); -} - -void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) -{ - delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(); - mAffectedAttribute = _sender; - mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); - mAttribDialog->setVisible(true); -} - -void CreateClassDialog::onAttributeSelected() -{ - ESM::Attribute::AttributeID id = mAttribDialog->getAttributeId(); - if (mAffectedAttribute == mFavoriteAttribute0) - { - if (mFavoriteAttribute1->getAttributeId() == id) - mFavoriteAttribute1->setAttributeId(mFavoriteAttribute0->getAttributeId()); - } - else if (mAffectedAttribute == mFavoriteAttribute1) - { - if (mFavoriteAttribute0->getAttributeId() == id) - mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); - } - mAffectedAttribute->setAttributeId(id); - MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); - mAttribDialog = 0; - - update(); -} - -void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) -{ - delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(); - mAffectedSkill = _sender; - mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); - mSkillDialog->setVisible(true); -} - -void CreateClassDialog::onSkillSelected() -{ - ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); - - // Avoid duplicate skills by swapping any skill field that matches the selected one - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) - { - if (*it == mAffectedSkill) - continue; - if ((*it)->getSkillId() == id) + int index = 0; + MWWorld::Store::iterator it = store.get().begin(); + for (; it != store.get().end(); ++it) { - (*it)->setSkillId(mAffectedSkill->getSkillId()); - break; + bool playable = (it->mData.mIsPlayable != 0); + if (!playable) // Only display playable classes + continue; + + const std::string &id = it->mId; + mClassList->addItem(it->mName, id); + if (mCurrentClassId.empty()) + { + mCurrentClassId = id; + mClassList->setIndexSelected(index); + } + else if (boost::iequals(id, mCurrentClassId)) + { + mClassList->setIndexSelected(index); + } + ++index; } } - mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); - mSkillDialog = 0; - update(); -} + void PickClassDialog::updateStats() + { + if (mCurrentClassId.empty()) + return; + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Class *klass = store.get().search(mCurrentClassId); + if (!klass) + return; -void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) -{ - mDescDialog = new DescriptionDialog(); - mDescDialog->setTextInput(mDescription); - mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); - mDescDialog->setVisible(true); -} + ESM::Class::Specialization specialization = static_cast(klass->mData.mSpecialization); -void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) -{ - mDescription = mDescDialog->getTextInput(); - MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); - mDescDialog = 0; -} + static const char *specIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); + mSpecializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); -void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(getName().size() <= 0) - return; - eventDone(this); -} + mFavoriteAttribute[0]->setAttributeId(klass->mData.mAttribute[0]); + mFavoriteAttribute[1]->setAttributeId(klass->mData.mAttribute[1]); + ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); -void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} + for (int i = 0; i < 5; ++i) + { + mMinorSkill[i]->setSkillNumber(klass->mData.mSkills[i][0]); + mMajorSkill[i]->setSkillNumber(klass->mData.mSkills[i][1]); + ToolTips::createSkillToolTip(mMinorSkill[i], klass->mData.mSkills[i][0]); + ToolTips::createSkillToolTip(mMajorSkill[i], klass->mData.mSkills[i][1]); + } -/* SelectSpecializationDialog */ + mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); + } -SelectSpecializationDialog::SelectSpecializationDialog() - : WindowModal("openmw_chargen_select_specialization.layout") -{ - // Centre dialog - center(); + /* InfoBoxDialog */ - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); + void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) + { + MyGUI::IntCoord inner = widget->getTextRegion(); + MyGUI::IntCoord outer = widget->getCoord(); + MyGUI::IntSize size = widget->getTextSize(); + size.width += outer.width - inner.width; + size.height += outer.height - inner.height; + widget->setSize(size); + } - getWidget(mSpecialization0, "Specialization0"); - getWidget(mSpecialization1, "Specialization1"); - getWidget(mSpecialization2, "Specialization2"); - std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); - std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); - std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) + { + size_t count = widget->getChildCount(); + int pos = 0; + pos += margin; + int width = 0; + for (unsigned i = 0; i < count; ++i) + { + MyGUI::Widget* child = widget->getChildAt(i); + if (!child->getVisible()) + continue; - mSpecialization0->setCaption(combat); - mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecialization1->setCaption(magic); - mSpecialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecialization2->setCaption(stealth); - mSpecialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecializationId = ESM::Class::Combat; + child->setPosition(child->getLeft(), pos); + width = std::max(width, child->getWidth()); + pos += child->getHeight() + margin; + } + width += margin*2; + widget->setSize(width, pos); + } - ToolTips::createSpecializationToolTip(mSpecialization0, combat, ESM::Class::Combat); - ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); - ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); + InfoBoxDialog::InfoBoxDialog() + : WindowModal("openmw_infobox.layout") + , mCurrentButton(-1) + { + getWidget(mTextBox, "TextBox"); + getWidget(mText, "Text"); + mText->getSubWidgetText()->setWordWrap(true); + getWidget(mButtonBar, "ButtonBar"); - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); -} + center(); + } -SelectSpecializationDialog::~SelectSpecializationDialog() -{ -} + void InfoBoxDialog::setText(const std::string &str) + { + mText->setCaption(str); + mTextBox->setVisible(!str.empty()); + fitToText(mText); + } -// widget controls + std::string InfoBoxDialog::getText() const + { + return mText->getCaption(); + } -void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender) -{ - if (_sender == mSpecialization0) + void InfoBoxDialog::setButtons(ButtonList &buttons) + { + for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + this->mButtons.clear(); + mCurrentButton = -1; + + // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget + MyGUI::Button* button; + MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); + ButtonList::const_iterator end = buttons.end(); + for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) + { + const std::string &text = *it; + button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); + button->getSubWidgetText()->setWordWrap(true); + button->setCaption(text); + fitToText(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); + coord.top += button->getHeight(); + this->mButtons.push_back(button); + } + } + + void InfoBoxDialog::open() + { + WindowModal::open(); + // Fix layout + layoutVertically(mTextBox, 4); + layoutVertically(mButtonBar, 6); + layoutVertically(mMainWidget, 4 + 6); + + center(); + } + + int InfoBoxDialog::getChosenButton() const + { + return mCurrentButton; + } + + void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) + { + std::vector::const_iterator end = mButtons.end(); + int i = 0; + for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) + { + if (*it == _sender) + { + mCurrentButton = i; + eventButtonSelected(i); + return; + } + ++i; + } + } + + /* ClassChoiceDialog */ + + ClassChoiceDialog::ClassChoiceDialog() + : InfoBoxDialog() + { + setText(""); + ButtonList buttons; + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); + setButtons(buttons); + } + + /* CreateClassDialog */ + + CreateClassDialog::CreateClassDialog() + : WindowModal("openmw_chargen_create_class.layout") + , mSpecDialog(NULL) + , mAttribDialog(NULL) + , mSkillDialog(NULL) + , mDescDialog(NULL) + { + // Centre dialog + center(); + + setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); + getWidget(mSpecializationName, "SpecializationName"); + mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); + + setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); + getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); + getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); + mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + + setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); + setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); + for(int i = 0; i < 5; i++) + { + char theIndex = '0'+i; + getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); + getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); + mSkills.push_back(mMajorSkill[i]); + mSkills.push_back(mMinorSkill[i]); + } + + std::vector::const_iterator end = mSkills.end(); + for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + { + (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + } + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); + getWidget(mEditName, "EditName"); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); + + MyGUI::Button* descriptionButton; + getWidget(descriptionButton, "DescriptionButton"); + descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); + + // Set default skills, attributes + + mFavoriteAttribute0->setAttributeId(ESM::Attribute::Strength); + mFavoriteAttribute1->setAttributeId(ESM::Attribute::Agility); + + mMajorSkill[0]->setSkillId(ESM::Skill::Block); + mMajorSkill[1]->setSkillId(ESM::Skill::Armorer); + mMajorSkill[2]->setSkillId(ESM::Skill::MediumArmor); + mMajorSkill[3]->setSkillId(ESM::Skill::HeavyArmor); + mMajorSkill[4]->setSkillId(ESM::Skill::BluntWeapon); + + mMinorSkill[0]->setSkillId(ESM::Skill::LongBlade); + mMinorSkill[1]->setSkillId(ESM::Skill::Axe); + mMinorSkill[2]->setSkillId(ESM::Skill::Spear); + mMinorSkill[3]->setSkillId(ESM::Skill::Athletics); + mMinorSkill[4]->setSkillId(ESM::Skill::Enchant); + + setSpecialization(0); + update(); + } + + CreateClassDialog::~CreateClassDialog() + { + delete mSpecDialog; + delete mAttribDialog; + delete mSkillDialog; + delete mDescDialog; + } + + void CreateClassDialog::update() + { + for (int i = 0; i < 5; ++i) + { + ToolTips::createSkillToolTip(mMajorSkill[i], mMajorSkill[i]->getSkillId()); + ToolTips::createSkillToolTip(mMinorSkill[i], mMinorSkill[i]->getSkillId()); + } + + ToolTips::createAttributeToolTip(mFavoriteAttribute0, mFavoriteAttribute0->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute1, mFavoriteAttribute1->getAttributeId()); + } + + std::string CreateClassDialog::getName() const + { + return mEditName->getOnlyText(); + } + + std::string CreateClassDialog::getDescription() const + { + return mDescription; + } + + ESM::Class::Specialization CreateClassDialog::getSpecializationId() const + { + return mSpecializationId; + } + + std::vector CreateClassDialog::getFavoriteAttributes() const + { + std::vector v; + v.push_back(mFavoriteAttribute0->getAttributeId()); + v.push_back(mFavoriteAttribute1->getAttributeId()); + return v; + } + + std::vector CreateClassDialog::getMajorSkills() const + { + std::vector v; + for(int i = 0; i < 5; i++) + { + v.push_back(mMajorSkill[i]->getSkillId()); + } + return v; + } + + std::vector CreateClassDialog::getMinorSkills() const + { + std::vector v; + for(int i=0; i < 5; i++) + { + v.push_back(mMinorSkill[i]->getSkillId()); + } + return v; + } + + void CreateClassDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + // widget controls + + void CreateClassDialog::onDialogCancel() + { + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); + mSpecDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); + mAttribDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); + mSkillDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); + mDescDialog = 0; + } + + void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) + { + delete mSpecDialog; + mSpecDialog = new SelectSpecializationDialog(); + mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); + mSpecDialog->setVisible(true); + } + + void CreateClassDialog::onSpecializationSelected() + { + mSpecializationId = mSpecDialog->getSpecializationId(); + setSpecialization(mSpecializationId); + + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); + mSpecDialog = 0; + } + + void CreateClassDialog::setSpecialization(int id) + { + mSpecializationId = (ESM::Class::Specialization) id; + static const char *specIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); + mSpecializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); + } + + void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) + { + delete mAttribDialog; + mAttribDialog = new SelectAttributeDialog(); + mAffectedAttribute = _sender; + mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); + mAttribDialog->setVisible(true); + } + + void CreateClassDialog::onAttributeSelected() + { + ESM::Attribute::AttributeID id = mAttribDialog->getAttributeId(); + if (mAffectedAttribute == mFavoriteAttribute0) + { + if (mFavoriteAttribute1->getAttributeId() == id) + mFavoriteAttribute1->setAttributeId(mFavoriteAttribute0->getAttributeId()); + } + else if (mAffectedAttribute == mFavoriteAttribute1) + { + if (mFavoriteAttribute0->getAttributeId() == id) + mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); + } + mAffectedAttribute->setAttributeId(id); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); + mAttribDialog = 0; + + update(); + } + + void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) + { + delete mSkillDialog; + mSkillDialog = new SelectSkillDialog(); + mAffectedSkill = _sender; + mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); + mSkillDialog->setVisible(true); + } + + void CreateClassDialog::onSkillSelected() + { + ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); + + // Avoid duplicate skills by swapping any skill field that matches the selected one + std::vector::const_iterator end = mSkills.end(); + for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + { + if (*it == mAffectedSkill) + continue; + if ((*it)->getSkillId() == id) + { + (*it)->setSkillId(mAffectedSkill->getSkillId()); + break; + } + } + + mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); + mSkillDialog = 0; + update(); + } + + void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) + { + mDescDialog = new DescriptionDialog(); + mDescDialog->setTextInput(mDescription); + mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); + mDescDialog->setVisible(true); + } + + void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) + { + mDescription = mDescDialog->getTextInput(); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); + mDescDialog = 0; + } + + void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(getName().size() <= 0) + return; + eventDone(this); + } + + void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + /* SelectSpecializationDialog */ + + SelectSpecializationDialog::SelectSpecializationDialog() + : WindowModal("openmw_chargen_select_specialization.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); + + getWidget(mSpecialization0, "Specialization0"); + getWidget(mSpecialization1, "Specialization1"); + getWidget(mSpecialization2, "Specialization2"); + std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); + std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); + std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + + mSpecialization0->setCaption(combat); + mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecialization1->setCaption(magic); + mSpecialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecialization2->setCaption(stealth); + mSpecialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); mSpecializationId = ESM::Class::Combat; - else if (_sender == mSpecialization1) - mSpecializationId = ESM::Class::Magic; - else if (_sender == mSpecialization2) - mSpecializationId = ESM::Class::Stealth; - else - return; - eventItemSelected(); -} + ToolTips::createSpecializationToolTip(mSpecialization0, combat, ESM::Class::Combat); + ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); + ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); -void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - -/* SelectAttributeDialog */ - -SelectAttributeDialog::SelectAttributeDialog() - : WindowModal("openmw_chargen_select_attribute.layout") -{ - // Centre dialog - center(); - - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); - - for (int i = 0; i < 8; ++i) - { - Widgets::MWAttributePtr attribute; - char theIndex = '0'+i; - - getWidget(attribute, std::string("Attribute").append(1, theIndex)); - attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); - attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); - ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); } - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); -} - -SelectAttributeDialog::~SelectAttributeDialog() -{ -} - -// widget controls - -void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) -{ - // TODO: Change MWAttribute to set and get AttributeID enum instead of int - mAttributeId = static_cast(_sender->getAttributeId()); - eventItemSelected(); -} - -void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - - -/* SelectSkillDialog */ - -SelectSkillDialog::SelectSkillDialog() - : WindowModal("openmw_chargen_select_skill.layout") -{ - // Centre dialog - center(); - - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); - setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); - setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); - setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); - - for(int i = 0; i < 9; i++) + SelectSpecializationDialog::~SelectSpecializationDialog() { - char theIndex = '0'+i; - getWidget(mCombatSkill[i], std::string("CombatSkill").append(1, theIndex)); - getWidget(mMagicSkill[i], std::string("MagicSkill").append(1, theIndex)); - getWidget(mStealthSkill[i], std::string("StealthSkill").append(1, theIndex)); } - struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} mSkills[3][9] = { + // widget controls + + void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender) + { + if (_sender == mSpecialization0) + mSpecializationId = ESM::Class::Combat; + else if (_sender == mSpecialization1) + mSpecializationId = ESM::Class::Magic; + else if (_sender == mSpecialization2) + mSpecializationId = ESM::Class::Stealth; + else + return; + + eventItemSelected(); + } + + void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + /* SelectAttributeDialog */ + + SelectAttributeDialog::SelectAttributeDialog() + : WindowModal("openmw_chargen_select_attribute.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); + + for (int i = 0; i < 8; ++i) { - {mCombatSkill[0], ESM::Skill::Block}, - {mCombatSkill[1], ESM::Skill::Armorer}, - {mCombatSkill[2], ESM::Skill::MediumArmor}, - {mCombatSkill[3], ESM::Skill::HeavyArmor}, - {mCombatSkill[4], ESM::Skill::BluntWeapon}, - {mCombatSkill[5], ESM::Skill::LongBlade}, - {mCombatSkill[6], ESM::Skill::Axe}, - {mCombatSkill[7], ESM::Skill::Spear}, - {mCombatSkill[8], ESM::Skill::Athletics} - }, - { - {mMagicSkill[0], ESM::Skill::Enchant}, - {mMagicSkill[1], ESM::Skill::Destruction}, - {mMagicSkill[2], ESM::Skill::Alteration}, - {mMagicSkill[3], ESM::Skill::Illusion}, - {mMagicSkill[4], ESM::Skill::Conjuration}, - {mMagicSkill[5], ESM::Skill::Mysticism}, - {mMagicSkill[6], ESM::Skill::Restoration}, - {mMagicSkill[7], ESM::Skill::Alchemy}, - {mMagicSkill[8], ESM::Skill::Unarmored} - }, - { - {mStealthSkill[0], ESM::Skill::Security}, - {mStealthSkill[1], ESM::Skill::Sneak}, - {mStealthSkill[2], ESM::Skill::Acrobatics}, - {mStealthSkill[3], ESM::Skill::LightArmor}, - {mStealthSkill[4], ESM::Skill::ShortBlade}, - {mStealthSkill[5] ,ESM::Skill::Marksman}, - {mStealthSkill[6] ,ESM::Skill::Mercantile}, - {mStealthSkill[7] ,ESM::Skill::Speechcraft}, - {mStealthSkill[8] ,ESM::Skill::HandToHand} + Widgets::MWAttributePtr attribute; + char theIndex = '0'+i; + + getWidget(attribute, std::string("Attribute").append(1, theIndex)); + attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); + attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); + ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); } - }; - for (int spec = 0; spec < 3; ++spec) - { - for (int i = 0; i < 9; ++i) - { - mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); - mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); - ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); - } + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); + } + + SelectAttributeDialog::~SelectAttributeDialog() + { + } + + // widget controls + + void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) + { + // TODO: Change MWAttribute to set and get AttributeID enum instead of int + mAttributeId = static_cast(_sender->getAttributeId()); + eventItemSelected(); + } + + void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + + /* SelectSkillDialog */ + + SelectSkillDialog::SelectSkillDialog() + : WindowModal("openmw_chargen_select_skill.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); + setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); + setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); + setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); + + for(int i = 0; i < 9; i++) + { + char theIndex = '0'+i; + getWidget(mCombatSkill[i], std::string("CombatSkill").append(1, theIndex)); + getWidget(mMagicSkill[i], std::string("MagicSkill").append(1, theIndex)); + getWidget(mStealthSkill[i], std::string("StealthSkill").append(1, theIndex)); + } + + struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} mSkills[3][9] = { + { + {mCombatSkill[0], ESM::Skill::Block}, + {mCombatSkill[1], ESM::Skill::Armorer}, + {mCombatSkill[2], ESM::Skill::MediumArmor}, + {mCombatSkill[3], ESM::Skill::HeavyArmor}, + {mCombatSkill[4], ESM::Skill::BluntWeapon}, + {mCombatSkill[5], ESM::Skill::LongBlade}, + {mCombatSkill[6], ESM::Skill::Axe}, + {mCombatSkill[7], ESM::Skill::Spear}, + {mCombatSkill[8], ESM::Skill::Athletics} + }, + { + {mMagicSkill[0], ESM::Skill::Enchant}, + {mMagicSkill[1], ESM::Skill::Destruction}, + {mMagicSkill[2], ESM::Skill::Alteration}, + {mMagicSkill[3], ESM::Skill::Illusion}, + {mMagicSkill[4], ESM::Skill::Conjuration}, + {mMagicSkill[5], ESM::Skill::Mysticism}, + {mMagicSkill[6], ESM::Skill::Restoration}, + {mMagicSkill[7], ESM::Skill::Alchemy}, + {mMagicSkill[8], ESM::Skill::Unarmored} + }, + { + {mStealthSkill[0], ESM::Skill::Security}, + {mStealthSkill[1], ESM::Skill::Sneak}, + {mStealthSkill[2], ESM::Skill::Acrobatics}, + {mStealthSkill[3], ESM::Skill::LightArmor}, + {mStealthSkill[4], ESM::Skill::ShortBlade}, + {mStealthSkill[5] ,ESM::Skill::Marksman}, + {mStealthSkill[6] ,ESM::Skill::Mercantile}, + {mStealthSkill[7] ,ESM::Skill::Speechcraft}, + {mStealthSkill[8] ,ESM::Skill::HandToHand} + } + }; + + for (int spec = 0; spec < 3; ++spec) + { + for (int i = 0; i < 9; ++i) + { + mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); + mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); + ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); + } + } + + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); + } + + SelectSkillDialog::~SelectSkillDialog() + { + } + + // widget controls + + void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender) + { + mSkillId = _sender->getSkillId(); + eventItemSelected(); + } + + void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + /* DescriptionDialog */ + + DescriptionDialog::DescriptionDialog() + : WindowModal("openmw_chargen_class_description.layout") + { + // Centre dialog + center(); + + getWidget(mTextEdit, "TextEdit"); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + } + + DescriptionDialog::~DescriptionDialog() + { + } + + // widget controls + + void DescriptionDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); } - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); -} - -SelectSkillDialog::~SelectSkillDialog() -{ -} - -// widget controls - -void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender) -{ - mSkillId = _sender->getSkillId(); - eventItemSelected(); -} - -void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - -/* DescriptionDialog */ - -DescriptionDialog::DescriptionDialog() - : WindowModal("openmw_chargen_class_description.layout") -{ - // Centre dialog - center(); - - getWidget(mTextEdit, "TextEdit"); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -DescriptionDialog::~DescriptionDialog() -{ -} - -// widget controls - -void DescriptionDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); } diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index bd1b0fe7a..463c645dc 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -278,16 +278,15 @@ namespace MWGui std::string Console::complete( std::string input, std::vector &matches ) { - using namespace std; - string output=input; - string tmp=input; + std::string output = input; + std::string tmp = input; bool has_front_quote = false; /* Does the input string contain things that don't have to be completed? If yes erase them. */ /* Are there quotation marks? */ - if( tmp.find('"') != string::npos ) { + if( tmp.find('"') != std::string::npos ) { int numquotes=0; - for(string::iterator it=tmp.begin(); it < tmp.end(); ++it) { + for(std::string::iterator it=tmp.begin(); it < tmp.end(); ++it) { if( *it == '"' ) numquotes++; } @@ -299,7 +298,7 @@ namespace MWGui } else { size_t pos; - if( ( ((pos = tmp.rfind(' ')) != string::npos ) ) && ( pos > tmp.rfind('"') ) ) { + if( ( ((pos = tmp.rfind(' ')) != std::string::npos ) ) && ( pos > tmp.rfind('"') ) ) { tmp.erase( 0, tmp.rfind(' ')+1); } else { @@ -311,7 +310,7 @@ namespace MWGui /* No quotation marks. Are there spaces?*/ else { size_t rpos; - if( (rpos=tmp.rfind(' ')) != string::npos ) { + if( (rpos=tmp.rfind(' ')) != std::string::npos ) { if( rpos == 0 ) { tmp.clear(); } @@ -330,7 +329,7 @@ namespace MWGui } /* Iterate through the vector. */ - for(vector::iterator it=mNames.begin(); it < mNames.end();++it) { + for(std::vector::iterator it=mNames.begin(); it < mNames.end();++it) { bool string_different=false; /* Is the string shorter than the input string? If yes skip it. */ @@ -338,7 +337,7 @@ namespace MWGui continue; /* Is the beginning of the string different from the input string? If yes skip it. */ - for( string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();iter++, iter2++) { + for( std::string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();iter++, iter2++) { if( tolower(*iter) != tolower(*iter2) ) { string_different=true; break; @@ -361,24 +360,24 @@ namespace MWGui /* Only one match. We're done. */ if( matches.size() == 1 ) { /* Adding quotation marks when the input string started with a quotation mark or has spaces in it*/ - if( ( matches.front().find(' ') != string::npos ) ) { + if( ( matches.front().find(' ') != std::string::npos ) ) { if( !has_front_quote ) - output.append(string("\"")); - return output.append(matches.front() + string("\" ")); + output.append(std::string("\"")); + return output.append(matches.front() + std::string("\" ")); } else if( has_front_quote ) { - return output.append(matches.front() + string("\" ")); + return output.append(matches.front() + std::string("\" ")); } else { - return output.append(matches.front() + string(" ")); + return output.append(matches.front() + std::string(" ")); } } /* Check if all matching strings match further than input. If yes complete to this match. */ int i = tmp.length(); - for(string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); iter++, i++) { - for(vector::iterator it=matches.begin(); it < matches.end();++it) { + for(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); iter++, i++) { + for(std::vector::iterator it=matches.begin(); it < matches.end();++it) { if( tolower((*it)[i]) != tolower(*iter) ) { /* Append the longest match to the end of the output string*/ output.append(matches.front().substr( 0, i)); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index d15a5acd3..16f253531 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -14,10 +14,6 @@ #include "tradewindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; -using namespace Widgets; - - namespace { bool compareType(std::string type1, std::string type2) @@ -68,686 +64,690 @@ namespace } } - -ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) - : mDragAndDrop(dragAndDrop) - , mFilter(ContainerBase::Filter_All) - , mDisplayEquippedItems(true) - , mHighlightEquippedItems(true) +namespace MWGui { -} -void ContainerBase::setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView) -{ - mContainerWidget = containerWidget; - mItemView = itemView; - - mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); - mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel); -} - -ContainerBase::~ContainerBase() -{ -} - -void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) -{ - mSelectedItem = _sender; - - if (mDragAndDrop && !isTrading()) + ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) + : mDragAndDrop(dragAndDrop) + , mFilter(ContainerBase::Filter_All) + , mDisplayEquippedItems(true) + , mHighlightEquippedItems(true) { - if(!mDragAndDrop->mIsOnDragAndDrop) + } + + void ContainerBase::setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView) + { + mContainerWidget = containerWidget; + mItemView = itemView; + + mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); + mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel); + } + + ContainerBase::~ContainerBase() + { + } + + void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) + { + mSelectedItem = _sender; + + if (mDragAndDrop && !isTrading()) + { + if(!mDragAndDrop->mIsOnDragAndDrop) + { + MWWorld::Ptr object = (*_sender->getUserData()); + int count = object.getRefData().getCount(); + + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + startDragItem(_sender, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + startDragItem(_sender, 1); + } + else + { + std::string message = "#{sTake}"; + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); + } + } + else + onContainerClicked(mContainerWidget); + } + else if (isTrading()) { MWWorld::Ptr object = (*_sender->getUserData()); int count = object.getRefData().getCount(); - if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + if (isInventory()) { - startDragItem(_sender, count); - } - else if (MyGUI::InputManager::getInstance().isControlPressed()) - { - startDragItem(_sender, 1); - } - else - { - std::string message = "#{sTake}"; - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), message, count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); - } - } - else - onContainerClicked(mContainerWidget); - } - else if (isTrading()) - { - MWWorld::Ptr object = (*_sender->getUserData()); - int count = object.getRefData().getCount(); - - if (isInventory()) - { - // the player is trying to sell an item, check if the merchant accepts it - if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) - { - // user notification "i don't buy this item" - MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog4}"); - return; - } - } - - bool buying = isTradeWindow(); // buying or selling? - std::string message = buying ? "#{sQuanityMenuMessage02}" : "#{sQuanityMenuMessage01}"; - - if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) - { - if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) - { - sellAlreadyBoughtItem(NULL, count); - } - else if (MyGUI::InputManager::getInstance().isControlPressed()) - { - sellAlreadyBoughtItem(NULL, 1); - } - else - { - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), message, count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem); - } - } - else - { - if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) - { - sellItem(NULL, count); - } - else if (MyGUI::InputManager::getInstance().isControlPressed()) - { - sellItem(NULL, 1); - } - else - { - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), message, count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); - } - } - } - else - { - onSelectedItemImpl(*_sender->getUserData()); - } -} - -void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) -{ - MWWorld::Ptr object = *mSelectedItem->getUserData(); - - if (isInventory()) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); - } - else - { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); - } - - std::string sound = MWWorld::Class::get(object).getUpSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - drawItems(); -} - -void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) -{ - MWWorld::Ptr object = *mSelectedItem->getUserData(); - - if (isInventory()) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); - } - else - { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); - } - - std::string sound = MWWorld::Class::get(object).getUpSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - drawItems(); -} - -void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count) -{ - mDragAndDrop->mIsOnDragAndDrop = true; - mSelectedItem->detachFromWidget(); - mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); - - MWWorld::Ptr object = *mSelectedItem->getUserData(); - _unequipItem(object); - - mDragAndDrop->mDraggedCount = count; - - mDragAndDrop->mDraggedFrom = this; - - std::string sound = MWWorld::Class::get(object).getUpSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - mDragAndDrop->mDraggedWidget = mSelectedItem; - static_cast(mSelectedItem)->setImageTexture(""); // remove the background texture (not visible during drag) - static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( - getCountString(mDragAndDrop->mDraggedCount)); - - drawItems(); - - MWBase::Environment::get().getWindowManager()->setDragDrop(true); -} - -void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) -{ - if (mDragAndDrop == NULL) return; - - if(mDragAndDrop->mIsOnDragAndDrop) //drop item here - { - MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - if (mDragAndDrop->mDraggedFrom != this) - { - assert(object.getContainerStore() && "Item is not in a container!"); - - // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside - if (mPtr.getTypeName() == typeid(ESM::Container).name()) - { - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mFlags & ESM::Container::Organic) + // the player is trying to sell an item, check if the merchant accepts it + if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) { - // user notification + // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage2}"); - + messageBox("#{sBarterDialog4}"); return; } } - int origCount = object.getRefData().getCount(); + bool buying = isTradeWindow(); // buying or selling? + std::string message = buying ? "#{sQuanityMenuMessage02}" : "#{sQuanityMenuMessage01}"; - // check that we don't exceed the allowed weight (only for containers, not for inventory) - if (!isInventory()) + if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) { - float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr); - - // try adding the item, and if weight is exceeded, just remove it again. - object.getRefData().setCount(mDragAndDrop->mDraggedCount); - MWWorld::ContainerStoreIterator it = containerStore.add(object); - - float curWeight = MWWorld::Class::get(mPtr).getEncumbrance(mPtr); - if (curWeight > capacity) + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) { - it->getRefData().setCount(0); - object.getRefData().setCount(origCount); - // user notification - MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage3}"); - - return; + sellAlreadyBoughtItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellAlreadyBoughtItem(NULL, 1); } else { - object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem); } } else { - object.getRefData().setCount (mDragAndDrop->mDraggedCount); - containerStore.add(object); - object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + sellItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellItem(NULL, 1); + } + else + { + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); + } } } + else + { + onSelectedItemImpl(*_sender->getUserData()); + } + } - mDragAndDrop->mIsOnDragAndDrop = false; - MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - drawItems(); - mDragAndDrop->mDraggedFrom->drawItems(); + void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) + { + MWWorld::Ptr object = *mSelectedItem->getUserData(); - mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); - notifyItemDragged(object, mDragAndDrop->mDraggedCount); + if (isInventory()) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); + } + else + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + } - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - - std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - } -} -void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mItemView->getViewOffset().left + _rel*0.3 > 0) - mItemView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0)); -} - -void ContainerBase::setFilter(int filter) -{ - mFilter = filter; - drawItems(); -} - -void ContainerBase::openContainer(MWWorld::Ptr container) -{ - mPtr = container; -} - -void ContainerBase::drawItems() -{ - while (mContainerWidget->getChildCount()) - { - MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); - } - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - int x = 0; - int y = 0; - int maxHeight = mItemView->getSize().height - 58; - - bool onlyMagic = false; - bool noMagic = false; - int categories = 0; - if (mFilter & Filter_All) - categories |= MWWorld::ContainerStore::Type_All; - if (mFilter & Filter_Weapon) - categories |= MWWorld::ContainerStore::Type_Weapon; - if (mFilter & Filter_Apparel) - categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor; - if (mFilter & Filter_Magic) - { - categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor - | MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Book - | MWWorld::ContainerStore::Type_Potion; - onlyMagic = true; - } - if (mFilter & Filter_Misc) - { - categories |= MWWorld::ContainerStore::Type_Miscellaneous | MWWorld::ContainerStore::Type_Book - | MWWorld::ContainerStore::Type_Ingredient | MWWorld::ContainerStore::Type_Repair - | MWWorld::ContainerStore::Type_Lockpick | MWWorld::ContainerStore::Type_Light - | MWWorld::ContainerStore::Type_Apparatus | MWWorld::ContainerStore::Type_Probe; - } - if (mFilter & Filter_Ingredients) - categories |= MWWorld::ContainerStore::Type_Ingredient; - if (mFilter & Filter_ChargedSoulstones) - categories |= MWWorld::ContainerStore::Type_Miscellaneous; - if (mFilter & Filter_NoMagic) - noMagic = true; - - /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them - - std::vector< std::pair > items; - - std::vector equippedItems = getEquippedItems(); - - // add bought items (always at the beginning) - std::vector boughtItems; - for (MWWorld::ContainerStoreIterator it (mBoughtItems.begin()); it!=mBoughtItems.end(); ++it) - { - boughtItems.push_back(*it); - } - std::sort(boughtItems.begin(), boughtItems.end(), sortItems); - - for (std::vector::iterator it=boughtItems.begin(); - it != boughtItems.end(); ++it) - { - items.push_back( std::make_pair(*it, ItemState_Barter) ); + drawItems(); } - // filter out the equipped items of categories we don't want - std::vector unwantedItems = equippedItems; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) { - std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *iter); - if (found != unwantedItems.end()) + MWWorld::Ptr object = *mSelectedItem->getUserData(); + + if (isInventory()) { - unwantedItems.erase(found); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } - } - // now erase everything that's still in unwantedItems. - for (std::vector::iterator it=unwantedItems.begin(); - it != unwantedItems.end(); ++it) - { - std::vector::iterator found = std::find(equippedItems.begin(), equippedItems.end(), *it); - assert(found != equippedItems.end()); - equippedItems.erase(found); - } - // and add the items that are left (= have the correct category) - if (mDisplayEquippedItems && mHighlightEquippedItems) - { - for (std::vector::const_iterator it=equippedItems.begin(); - it != equippedItems.end(); ++it) + else { - items.push_back( std::make_pair(*it, ItemState_Equipped) ); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + drawItems(); } - std::vector ignoreItems = itemsToIgnore(); - - // now add the regular items - std::vector regularItems; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count) { - if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() - || (!mHighlightEquippedItems && mDisplayEquippedItems)) - && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() - && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) - regularItems.push_back(*iter); + mDragAndDrop->mIsOnDragAndDrop = true; + mSelectedItem->detachFromWidget(); + mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); + + MWWorld::Ptr object = *mSelectedItem->getUserData(); + _unequipItem(object); + + mDragAndDrop->mDraggedCount = count; + + mDragAndDrop->mDraggedFrom = this; + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + mDragAndDrop->mDraggedWidget = mSelectedItem; + static_cast(mSelectedItem)->setImageTexture(""); // remove the background texture (not visible during drag) + static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( + getCountString(mDragAndDrop->mDraggedCount)); + + drawItems(); + + MWBase::Environment::get().getWindowManager()->setDragDrop(true); } - // sort them and add - std::sort(regularItems.begin(), regularItems.end(), sortItems); - for (std::vector::const_iterator it=regularItems.begin(); it!=regularItems.end(); ++it) + void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { - items.push_back( std::make_pair(*it, ItemState_Normal) ); - } + if (mDragAndDrop == NULL) return; - for (std::vector< std::pair >::const_iterator it=items.begin(); - it != items.end(); ++it) - { - const MWWorld::Ptr* iter = &((*it).first); - - - if (onlyMagic - && it->second != ItemState_Barter - && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" - && iter->getTypeName() != typeid(ESM::Potion).name()) - continue; - - if (noMagic - && it->second != ItemState_Barter - && (MWWorld::Class::get(*iter).getEnchantment(*iter) != "" - || iter->getTypeName() == typeid(ESM::Potion).name())) - continue; - - if ( (mFilter & Filter_ChargedSoulstones) - && !isChargedSoulstone(*iter)) - continue; - - int displayCount = iter->getRefData().getCount(); - if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + if(mDragAndDrop->mIsOnDragAndDrop) //drop item here { - displayCount -= mDragAndDrop->mDraggedCount; - } - if(displayCount > 0) - { - std::string path = std::string("icons\\"); - path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - // background widget (for the "equipped" frame and magic item background image) - bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); - MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); - backgroundWidget->setUserString("ToolTipType", "ItemPtr"); - backgroundWidget->setUserData(*iter); - - std::string backgroundTex = "textures\\menu_icon"; - if (isMagic) - backgroundTex += "_magic"; - if (it->second == ItemState_Normal) + if (mDragAndDrop->mDraggedFrom != this) { - if (!isMagic) - backgroundTex = ""; - } - else if (it->second == ItemState_Equipped) - { - backgroundTex += "_equip"; - } - else if (it->second == ItemState_Barter) - { - backgroundTex += "_barter"; - } - if (backgroundTex != "") - backgroundTex += ".dds"; + assert(object.getContainerStore() && "Item is not in a container!"); - backgroundWidget->setImageTexture(backgroundTex); - if (it->second == ItemState_Barter && !isMagic) - backgroundWidget->setProperty("ImageCoord", "2 2 42 42"); - else - backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); - backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem); - backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel); + // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside + if (mPtr.getTypeName() == typeid(ESM::Container).name()) + { + MWWorld::LiveCellRef* ref = mPtr.get(); + if (ref->mBase->mFlags & ESM::Container::Organic) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sContentsMessage2}"); - // image - MyGUI::ImageBox* image = backgroundWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); - int pos = path.rfind("."); - path.erase(pos); - path.append(".dds"); - image->setImageTexture(path); - image->setNeedMouseFocus(false); + return; + } + } - // text widget that shows item count - MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); - text->setTextAlign(MyGUI::Align::Right); - text->setNeedMouseFocus(false); - text->setTextShadow(true); - text->setTextShadowColour(MyGUI::Colour(0,0,0)); - text->setCaption(getCountString(displayCount)); + int origCount = object.getRefData().getCount(); - y += 42; - if (y > maxHeight) - { - x += 42; - y = 0; + // check that we don't exceed the allowed weight (only for containers, not for inventory) + if (!isInventory()) + { + float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr); + + // try adding the item, and if weight is exceeded, just remove it again. + object.getRefData().setCount(mDragAndDrop->mDraggedCount); + MWWorld::ContainerStoreIterator it = containerStore.add(object); + + float curWeight = MWWorld::Class::get(mPtr).getEncumbrance(mPtr); + if (curWeight > capacity) + { + it->getRefData().setCount(0); + object.getRefData().setCount(origCount); + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sContentsMessage3}"); + + return; + } + else + { + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + } + } + else + { + object.getRefData().setCount (mDragAndDrop->mDraggedCount); + containerStore.add(object); + object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); + } } + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + drawItems(); + mDragAndDrop->mDraggedFrom->drawItems(); + + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); + notifyItemDragged(object, mDragAndDrop->mDraggedCount); + + MWBase::Environment::get().getWindowManager()->setDragDrop(false); + + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } } - MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); - mItemView->setCanvasSize(size); - mContainerWidget->setSize(size); - - notifyContentChanged(); -} - -std::string ContainerBase::getCountString(const int count) -{ - if (count == 1) - return ""; - if (count > 9999) - return boost::lexical_cast(int(count/1000.f)) + "k"; - else - return boost::lexical_cast(count); -} - -void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) -{ - int origCount = item.getRefData().getCount(); - item.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = mBoughtItems.add(item); - item.getRefData().setCount(origCount - count); -} - -void ContainerBase::addItem(MWWorld::Ptr item, int count) -{ - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - int origCount = item.getRefData().getCount(); - - item.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = containerStore.add(item); - - item.getRefData().setCount(origCount - count); -} - -void ContainerBase::transferBoughtItems() -{ - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - containerStore.add(*it); + if (mItemView->getViewOffset().left + _rel*0.3 > 0) + mItemView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0)); } -} -void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) -{ - for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + void ContainerBase::setFilter(int filter) { - store.add(*it); + mFilter = filter; + drawItems(); } -} -std::vector ContainerBase::getEquippedItems() -{ - if (mPtr.getTypeName() != typeid(ESM::NPC).name()) - return std::vector(); - - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - - std::vector items; - - for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + void ContainerBase::openContainer(MWWorld::Ptr container) { - MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); - if (it != invStore.end()) + mPtr = container; + } + + void ContainerBase::drawItems() + { + while (mContainerWidget->getChildCount()) { - items.push_back(*it); + MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); } - } - - return items; -} - -MWWorld::ContainerStore& ContainerBase::getContainerStore() -{ - MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - return store; -} - -// ------------------------------------------------------------------------------------------------ - -ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) - : ContainerBase(dragAndDrop) - , WindowBase("openmw_container_window.layout") -{ - getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); - getWidget(mTakeButton, "TakeButton"); - getWidget(mCloseButton, "CloseButton"); - - MyGUI::ScrollView* itemView; - MyGUI::Widget* containerWidget; - getWidget(containerWidget, "Items"); - getWidget(itemView, "ItemView"); - setWidgets(containerWidget, itemView); - - mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); - - static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); - - setCoord(200,0,600,300); -} - -ContainerWindow::~ContainerWindow() -{ -} - -void ContainerWindow::onWindowResize(MyGUI::Window* window) -{ - drawItems(); -} - -void ContainerWindow::open(MWWorld::Ptr container, bool loot) -{ - mDisplayEquippedItems = true; - mHighlightEquippedItems = false; - if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) - { - // we are stealing stuff - mDisplayEquippedItems = false; - } - - mDisposeCorpseButton->setVisible(loot); - - openContainer(container); - setTitle(MWWorld::Class::get(container).getName(container)); - drawItems(); -} - -void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); - } -} - -void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - // transfer everything into the player's inventory MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + int x = 0; + int y = 0; + int maxHeight = mItemView->getSize().height - 58; + + bool onlyMagic = false; + bool noMagic = false; + int categories = 0; + if (mFilter & Filter_All) + categories |= MWWorld::ContainerStore::Type_All; + if (mFilter & Filter_Weapon) + categories |= MWWorld::ContainerStore::Type_Weapon; + if (mFilter & Filter_Apparel) + categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor; + if (mFilter & Filter_Magic) + { + categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor + | MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Book + | MWWorld::ContainerStore::Type_Potion; + onlyMagic = true; + } + if (mFilter & Filter_Misc) + { + categories |= MWWorld::ContainerStore::Type_Miscellaneous | MWWorld::ContainerStore::Type_Book + | MWWorld::ContainerStore::Type_Ingredient | MWWorld::ContainerStore::Type_Repair + | MWWorld::ContainerStore::Type_Lockpick | MWWorld::ContainerStore::Type_Light + | MWWorld::ContainerStore::Type_Apparatus | MWWorld::ContainerStore::Type_Probe; + } + if (mFilter & Filter_Ingredients) + categories |= MWWorld::ContainerStore::Type_Ingredient; + if (mFilter & Filter_ChargedSoulstones) + categories |= MWWorld::ContainerStore::Type_Miscellaneous; + if (mFilter & Filter_NoMagic) + noMagic = true; + + /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them + + std::vector< std::pair > items; + std::vector equippedItems = getEquippedItems(); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); - - int i=0; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + // add bought items (always at the beginning) + std::vector boughtItems; + for (MWWorld::ContainerStoreIterator it (mBoughtItems.begin()); it!=mBoughtItems.end(); ++it) { - if (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() - && !mDisplayEquippedItems) - continue; + boughtItems.push_back(*it); + } + std::sort(boughtItems.begin(), boughtItems.end(), sortItems); - playerStore.add(*iter); - - if (i==0) - { - // play the sound of the first object - std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - } - - iter->getRefData().setCount(0); - - ++i; + for (std::vector::iterator it=boughtItems.begin(); + it != boughtItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Barter) ); } + // filter out the equipped items of categories we don't want + std::vector unwantedItems = equippedItems; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + { + std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *iter); + if (found != unwantedItems.end()) + { + unwantedItems.erase(found); + } + } + // now erase everything that's still in unwantedItems. + for (std::vector::iterator it=unwantedItems.begin(); + it != unwantedItems.end(); ++it) + { + std::vector::iterator found = std::find(equippedItems.begin(), equippedItems.end(), *it); + assert(found != equippedItems.end()); + equippedItems.erase(found); + } + // and add the items that are left (= have the correct category) + if (mDisplayEquippedItems && mHighlightEquippedItems) + { + for (std::vector::const_iterator it=equippedItems.begin(); + it != equippedItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Equipped) ); + } + } + + std::vector ignoreItems = itemsToIgnore(); + + // now add the regular items + std::vector regularItems; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + { + if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() + || (!mHighlightEquippedItems && mDisplayEquippedItems)) + && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() + && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) + regularItems.push_back(*iter); + } + + // sort them and add + std::sort(regularItems.begin(), regularItems.end(), sortItems); + for (std::vector::const_iterator it=regularItems.begin(); it!=regularItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Normal) ); + } + + for (std::vector< std::pair >::const_iterator it=items.begin(); + it != items.end(); ++it) + { + const MWWorld::Ptr* iter = &((*it).first); + + + if (onlyMagic + && it->second != ItemState_Barter + && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" + && iter->getTypeName() != typeid(ESM::Potion).name()) + continue; + + if (noMagic + && it->second != ItemState_Barter + && (MWWorld::Class::get(*iter).getEnchantment(*iter) != "" + || iter->getTypeName() == typeid(ESM::Potion).name())) + continue; + + if ( (mFilter & Filter_ChargedSoulstones) + && !isChargedSoulstone(*iter)) + continue; + + int displayCount = iter->getRefData().getCount(); + if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + { + displayCount -= mDragAndDrop->mDraggedCount; + } + if(displayCount > 0) + { + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + + // background widget (for the "equipped" frame and magic item background image) + bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); + MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); + backgroundWidget->setUserString("ToolTipType", "ItemPtr"); + backgroundWidget->setUserData(*iter); + + std::string backgroundTex = "textures\\menu_icon"; + if (isMagic) + backgroundTex += "_magic"; + if (it->second == ItemState_Normal) + { + if (!isMagic) + backgroundTex = ""; + } + else if (it->second == ItemState_Equipped) + { + backgroundTex += "_equip"; + } + else if (it->second == ItemState_Barter) + { + backgroundTex += "_barter"; + } + if (backgroundTex != "") + backgroundTex += ".dds"; + + backgroundWidget->setImageTexture(backgroundTex); + if (it->second == ItemState_Barter && !isMagic) + backgroundWidget->setProperty("ImageCoord", "2 2 42 42"); + else + backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); + backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem); + backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel); + + // image + MyGUI::ImageBox* image = backgroundWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture(path); + image->setNeedMouseFocus(false); + + // text widget that shows item count + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); + text->setTextAlign(MyGUI::Align::Right); + text->setNeedMouseFocus(false); + text->setTextShadow(true); + text->setTextShadowColour(MyGUI::Colour(0,0,0)); + text->setCaption(getCountString(displayCount)); + + y += 42; + if (y > maxHeight) + { + x += 42; + y = 0; + } + + } + } + + MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); + mItemView->setCanvasSize(size); + mContainerWidget->setSize(size); + + notifyContentChanged(); + } + + std::string ContainerBase::getCountString(const int count) + { + if (count == 1) + return ""; + if (count > 9999) + return boost::lexical_cast(int(count/1000.f)) + "k"; + else + return boost::lexical_cast(count); + } + + void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) + { + int origCount = item.getRefData().getCount(); + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = mBoughtItems.add(item); + item.getRefData().setCount(origCount - count); + } + + void ContainerBase::addItem(MWWorld::Ptr item, int count) + { + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + int origCount = item.getRefData().getCount(); + + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = containerStore.add(item); + + item.getRefData().setCount(origCount - count); + } + + void ContainerBase::transferBoughtItems() + { + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + containerStore.add(*it); + } + } + + void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) + { + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + store.add(*it); + } + } + + std::vector ContainerBase::getEquippedItems() + { + if (mPtr.getTypeName() != typeid(ESM::NPC).name()) + return std::vector(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + + std::vector items; + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) + { + items.push_back(*it); + } + } + + return items; + } + + MWWorld::ContainerStore& ContainerBase::getContainerStore() + { + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + return store; + } + + // ------------------------------------------------------------------------------------------------ + + ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) + : ContainerBase(dragAndDrop) + , WindowBase("openmw_container_window.layout") + { + getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); + getWidget(mTakeButton, "TakeButton"); + getWidget(mCloseButton, "CloseButton"); + + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); + + setCoord(200,0,600,300); + } + + ContainerWindow::~ContainerWindow() + { + } + + void ContainerWindow::onWindowResize(MyGUI::Window* window) + { + drawItems(); + } + + void ContainerWindow::open(MWWorld::Ptr container, bool loot) + { + mDisplayEquippedItems = true; + mHighlightEquippedItems = false; + if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) + { + // we are stealing stuff + mDisplayEquippedItems = false; + } + + mDisposeCorpseButton->setVisible(loot); + + openContainer(container); + setTitle(MWWorld::Class::get(container).getName(container)); + drawItems(); + } + + void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } + } + + void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + // transfer everything into the player's inventory + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + std::vector equippedItems = getEquippedItems(); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); + + int i=0; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + { + if (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() + && !mDisplayEquippedItems) + continue; + + playerStore.add(*iter); + + if (i==0) + { + // play the sound of the first object + std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + } + + iter->getRefData().setCount(0); + + ++i; + } + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } + } + + void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + onTakeAllButtonClicked(mTakeButton); + + /// \todo I don't think this is the correct flag to check + if (MWWorld::Class::get(mPtr).isEssential(mPtr)) + MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); + else + MWBase::Environment::get().getWorld()->deleteObject(mPtr); + + mPtr = MWWorld::Ptr(); + } + } + + void ContainerWindow::onReferenceUnavailable() + { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } -} - -void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - onTakeAllButtonClicked(mTakeButton); - - /// \todo I don't think this is the correct flag to check - if (MWWorld::Class::get(mPtr).isEssential(mPtr)) - MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); - else - MWBase::Environment::get().getWorld()->deleteObject(mPtr); - - mPtr = MWWorld::Ptr(); - } -} - -void ContainerWindow::onReferenceUnavailable() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 392f64126..b596cef01 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -19,521 +19,521 @@ #include "inventorywindow.hpp" #include "travelwindow.hpp" -using namespace MWGui; -using namespace Widgets; - /** *Copied from the internet. */ -namespace { - -std::string lower_string(const std::string& str) +namespace { - std::string lowerCase = Misc::StringUtils::lowerCase (str); - return lowerCase; -} - -std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) -{ - return lower_string(str).find(lower_string(substr),pos); -} - -bool sortByLength (const std::string& left, const std::string& right) -{ - return left.size() > right.size(); -} -} - - - -PersuasionDialog::PersuasionDialog() - : WindowModal("openmw_persuasion_dialog.layout") -{ - getWidget(mCancelButton, "CancelButton"); - getWidget(mAdmireButton, "AdmireButton"); - getWidget(mIntimidateButton, "IntimidateButton"); - getWidget(mTauntButton, "TauntButton"); - getWidget(mBribe10Button, "Bribe10Button"); - getWidget(mBribe100Button, "Bribe100Button"); - getWidget(mBribe1000Button, "Bribe1000Button"); - getWidget(mGoldLabel, "GoldLabel"); - - mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); - mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); -} - -void PersuasionDialog::onCancel(MyGUI::Widget *sender) -{ - setVisible(false); -} - -void PersuasionDialog::onPersuade(MyGUI::Widget *sender) -{ - MWBase::MechanicsManager::PersuasionType type; - if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; - else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; - else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; - else if (sender == mBribe10Button) + std::string lower_string(const std::string& str) { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); - type = MWBase::MechanicsManager::PT_Bribe10; - } - else if (sender == mBribe100Button) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); - type = MWBase::MechanicsManager::PT_Bribe100; - } - else /*if (sender == mBribe1000Button)*/ - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); - type = MWBase::MechanicsManager::PT_Bribe1000; + std::string lowerCase = Misc::StringUtils::lowerCase (str); + + return lowerCase; } - MWBase::Environment::get().getDialogueManager()->persuade(type); - - setVisible(false); -} - -void PersuasionDialog::open() -{ - WindowModal::open(); - center(); - - int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); - - mBribe10Button->setEnabled (playerGold >= 10); - mBribe100Button->setEnabled (playerGold >= 100); - mBribe1000Button->setEnabled (playerGold >= 1000); - - mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); -} - -// -------------------------------------------------------------------------------------------------- - -DialogueWindow::DialogueWindow() - : WindowBase("openmw_dialogue_window.layout") - , mPersuasionDialog() - , mEnabled(false) - , mServices(0) -{ - // Centre dialog - center(); - - mPersuasionDialog.setVisible(false); - - //History view - getWidget(mHistory, "History"); - mHistory->setOverflowToTheLeft(true); - mHistory->setMaxTextLength(1000000); - MyGUI::Widget* eventbox; - - //An EditBox cannot receive mouse click events, so we use an - //invisible widget on top of the editbox to receive them - getWidget(eventbox, "EventBox"); - eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); - eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); - - //Topics list - getWidget(mTopicsList, "TopicsList"); - mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); - byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); - - getWidget(mDispositionBar, "Disposition"); - getWidget(mDispositionText,"DispositionText"); - - static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); -} - -void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) -{ - MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); - if(t == NULL) - return; - - const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); - - size_t cursorPosition = t->getCursorPosition(lastPressed); - MyGUI::UString color = mHistory->getColorAtPos(cursorPosition); - - if (!mEnabled && color == "#572D21") - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - - if (!mEnabled) - return; - - if(color != "#B29154") + std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) { - MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); + return lower_string(str).find(lower_string(substr),pos); + } - if(color == "#686EBA") + bool sortByLength (const std::string& left, const std::string& right) + { + return left.size() > right.size(); + } +} + +namespace MWGui +{ + + PersuasionDialog::PersuasionDialog() + : WindowModal("openmw_persuasion_dialog.layout") + { + getWidget(mCancelButton, "CancelButton"); + getWidget(mAdmireButton, "AdmireButton"); + getWidget(mIntimidateButton, "IntimidateButton"); + getWidget(mTauntButton, "TauntButton"); + getWidget(mBribe10Button, "Bribe10Button"); + getWidget(mBribe100Button, "Bribe100Button"); + getWidget(mBribe1000Button, "Bribe1000Button"); + getWidget(mGoldLabel, "GoldLabel"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); + mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + } + + void PersuasionDialog::onCancel(MyGUI::Widget *sender) + { + setVisible(false); + } + + void PersuasionDialog::onPersuade(MyGUI::Widget *sender) + { + MWBase::MechanicsManager::PersuasionType type; + if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; + else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; + else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; + else if (sender == mBribe10Button) { - std::map::iterator i = mHyperLinks.upper_bound(cursorPosition); - if( !mHyperLinks.empty() ) - { - --i; - - if( i->first + i->second.mLength > cursorPosition) - { - MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue); - } - } - else - { - // the link was colored, but it is not in mHyperLinks. - // It means that those liunks are not marked with @# and found - // by topic name search - MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); - } + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); + type = MWBase::MechanicsManager::PT_Bribe10; + } + else if (sender == mBribe100Button) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); + type = MWBase::MechanicsManager::PT_Bribe100; + } + else /*if (sender == mBribe1000Button)*/ + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); + type = MWBase::MechanicsManager::PT_Bribe1000; } - if(color == "#572D21") - MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); - } -} + MWBase::Environment::get().getDialogueManager()->persuade(type); -void DialogueWindow::onWindowResize(MyGUI::Window* _sender) -{ - mTopicsList->adjustSize(); -} - -void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mHistory->getVScrollPosition() - _rel*0.3 < 0) - mHistory->setVScrollPosition(0); - else - mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3); -} - -void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); -} - -void DialogueWindow::onSelectTopic(const std::string& topic, int id) -{ - if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) - return; - - int separatorPos = 0; - for (unsigned int i=0; igetItemCount(); ++i) - { - if (mTopicsList->getItemNameAt(i) == "") - separatorPos = i; + setVisible(false); } - if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); - else + void PersuasionDialog::open() { + WindowModal::open(); + center(); + + int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); + + mBribe10Button->setEnabled (playerGold >= 10); + mBribe100Button->setEnabled (playerGold >= 100); + mBribe1000Button->setEnabled (playerGold >= 1000); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + } + + // -------------------------------------------------------------------------------------------------- + + DialogueWindow::DialogueWindow() + : WindowBase("openmw_dialogue_window.layout") + , mPersuasionDialog() + , mEnabled(false) + , mServices(0) + { + // Centre dialog + center(); + + mPersuasionDialog.setVisible(false); + + //History view + getWidget(mHistory, "History"); + mHistory->setOverflowToTheLeft(true); + mHistory->setMaxTextLength(1000000); + MyGUI::Widget* eventbox; + + //An EditBox cannot receive mouse click events, so we use an + //invisible widget on top of the editbox to receive them + getWidget(eventbox, "EventBox"); + eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); + eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); + + //Topics list + getWidget(mTopicsList, "TopicsList"); + mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + + MyGUI::Button* byeButton; + getWidget(byeButton, "ByeButton"); + byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); + + getWidget(mDispositionBar, "Disposition"); + getWidget(mDispositionText,"DispositionText"); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); + } + + void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) + { + MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); + if(t == NULL) + return; + + const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + + size_t cursorPosition = t->getCursorPosition(lastPressed); + MyGUI::UString color = mHistory->getColorAtPos(cursorPosition); + + if (!mEnabled && color == "#572D21") + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + + if (!mEnabled) + return; + + if(color != "#B29154") + { + MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); + + if(color == "#686EBA") + { + std::map::iterator i = mHyperLinks.upper_bound(cursorPosition); + if( !mHyperLinks.empty() ) + { + --i; + + if( i->first + i->second.mLength > cursorPosition) + { + MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue); + } + } + else + { + // the link was colored, but it is not in mHyperLinks. + // It means that those liunks are not marked with @# and found + // by topic name search + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); + } + } + + if(color == "#572D21") + MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); + } + } + + void DialogueWindow::onWindowResize(MyGUI::Window* _sender) + { + mTopicsList->adjustSize(); + } + + void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mHistory->getVScrollPosition() - _rel*0.3 < 0) + mHistory->setVScrollPosition(0); + else + mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3); + } + + void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) + { + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + } + + void DialogueWindow::onSelectTopic(const std::string& topic, int id) + { + if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + return; + + int separatorPos = 0; + for (unsigned int i=0; igetItemCount(); ++i) + { + if (mTopicsList->getItemNameAt(i) == "") + separatorPos = i; + } + + if (id >= separatorPos) + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); + else + { + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (topic == gmst.find("sPersuasion")->getString()) + { + mPersuasionDialog.setVisible(true); + } + else if (topic == gmst.find("sCompanionShare")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); + MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + } + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + { + if (topic == gmst.find("sBarter")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); + } + else if (topic == gmst.find("sSpells")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); + } + else if (topic == gmst.find("sTravel")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); + } + else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); + } + else if (topic == gmst.find("sEnchanting")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); + MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); + } + else if (topic == gmst.find("sServiceTrainingTitle")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->startTraining (mPtr); + } + else if (topic == gmst.find("sRepair")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + } + } + } + } + + void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) + { + mEnabled = true; + mPtr = actor; + mTopicsList->setEnabled(true); + setTitle(npcName); + + mTopicsList->clear(); + mHyperLinks.clear(); + mHistory->setCaption(""); + updateOptions(); + } + + void DialogueWindow::setKeywords(std::list keyWords) + { + mTopicsList->clear(); + + bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty() + && mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion"); + + bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); + const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (topic == gmst.find("sPersuasion")->getString()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + mTopicsList->addItem(gmst.find("sPersuasion")->getString()); + + if (mServices & Service_Trade) + mTopicsList->addItem(gmst.find("sBarter")->getString()); + + if (mServices & Service_BuySpells) + mTopicsList->addItem(gmst.find("sSpells")->getString()); + + if (mServices & Service_Travel) + mTopicsList->addItem(gmst.find("sTravel")->getString()); + + if (mServices & Service_CreateSpells) + mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); + + if (mServices & Service_Enchant) + mTopicsList->addItem(gmst.find("sEnchanting")->getString()); + + if (mServices & Service_Training) + mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); + + if (mServices & Service_Repair) + mTopicsList->addItem(gmst.find("sRepair")->getString()); + + if (isCompanion) + mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); + + if (anyService) + mTopicsList->addSeparator(); + + + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) { - mPersuasionDialog.setVisible(true); + mTopicsList->addItem(*it); } - else if (topic == gmst.find("sCompanionShare")->getString()) + mTopicsList->adjustSize(); + } + + void DialogueWindow::removeKeyword(std::string keyWord) + { + if(mTopicsList->hasItem(keyWord)) { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + mTopicsList->removeItem(keyWord); } - else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + mTopicsList->adjustSize(); + } + + void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) + { + size_t pos = 0; + while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) { - if (topic == gmst.find("sBarter")->getString()) + // do not add color if this portion of text is already colored. { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); - } - else if (topic == gmst.find("sSpells")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); - } - else if (topic == gmst.find("sTravel")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); - } - else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); - MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); - } - else if (topic == gmst.find("sEnchanting")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); - MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); - } - else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); - MWBase::Environment::get().getWindowManager()->startTraining (mPtr); - } - else if (topic == gmst.find("sRepair")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); - MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + MyGUI::TextIterator iterator (str); + MyGUI::UString colour; + while(iterator.moveNext()) + { + size_t iteratorPos = iterator.getPosition(); + iterator.getTagColour(colour); + if (iteratorPos == pos) + break; + } + + if (colour == color1) + return; } + + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); } } -} -void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) -{ - mEnabled = true; - mPtr = actor; - mTopicsList->setEnabled(true); - setTitle(npcName); - - mTopicsList->clear(); - mHyperLinks.clear(); - mHistory->setCaption(""); - updateOptions(); -} - -void DialogueWindow::setKeywords(std::list keyWords) -{ - mTopicsList->clear(); - - bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion"); - - bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); - - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) - mTopicsList->addItem(gmst.find("sPersuasion")->getString()); - - if (mServices & Service_Trade) - mTopicsList->addItem(gmst.find("sBarter")->getString()); - - if (mServices & Service_BuySpells) - mTopicsList->addItem(gmst.find("sSpells")->getString()); - - if (mServices & Service_Travel) - mTopicsList->addItem(gmst.find("sTravel")->getString()); - - if (mServices & Service_CreateSpells) - mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); - - if (mServices & Service_Enchant) - mTopicsList->addItem(gmst.find("sEnchanting")->getString()); - - if (mServices & Service_Training) - mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); - - if (mServices & Service_Repair) - mTopicsList->addItem(gmst.find("sRepair")->getString()); - - if (isCompanion) - mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); - - if (anyService) - mTopicsList->addSeparator(); - - - for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) + std::string DialogueWindow::parseText(const std::string& text) { - mTopicsList->addItem(*it); - } - mTopicsList->adjustSize(); -} + bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) -void DialogueWindow::removeKeyword(std::string keyWord) -{ - if(mTopicsList->hasItem(keyWord)) - { - mTopicsList->removeItem(keyWord); - } - mTopicsList->adjustSize(); -} + std::vector topics; -void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) -{ - size_t pos = 0; - while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) - { - // do not add color if this portion of text is already colored. + bool hasSeparator = false; + for (unsigned int i=0; igetItemCount(); ++i) { - MyGUI::TextIterator iterator (str); - MyGUI::UString colour; - while(iterator.moveNext()) - { - size_t iteratorPos = iterator.getPosition(); - iterator.getTagColour(colour); - if (iteratorPos == pos) - break; - } - - if (colour == color1) - return; + if (mTopicsList->getItemNameAt(i) == "") + hasSeparator = true; } - str.insert(pos,color1); - pos += color1.length(); - pos += keyword.length(); - str.insert(pos,color2); - pos+= color2.length(); - } -} - -std::string DialogueWindow::parseText(const std::string& text) -{ - bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) - - std::vector topics; - - bool hasSeparator = false; - for (unsigned int i=0; igetItemCount(); ++i) - { - if (mTopicsList->getItemNameAt(i) == "") - hasSeparator = true; - } - - for(unsigned int i = 0;igetItemCount();i++) - { - std::string keyWord = mTopicsList->getItemNameAt(i); - if (separatorReached || !hasSeparator) - topics.push_back(keyWord); - else if (keyWord == "") - separatorReached = true; - } - - // sort by length to make sure longer topics are replaced first - std::sort(topics.begin(), topics.end(), sortByLength); - - std::vector hypertext = MWDialogue::ParseHyperText(text); - - size_t historySize = 0; - if(mHistory->getClient()->getSubWidgetText() != NULL) - { - historySize = mHistory->getOnlyText().size(); - } - - std::string result; - size_t hypertextPos = 0; - for (size_t i = 0; i < hypertext.size(); ++i) - { - if (hypertext[i].mLink) + for(unsigned int i = 0;igetItemCount();i++) { - size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); - std::string standardForm = hypertext[i].mText; - for(; asterisk_count > 0; --asterisk_count) - standardForm.append("*"); + std::string keyWord = mTopicsList->getItemNameAt(i); + if (separatorReached || !hasSeparator) + topics.push_back(keyWord); + else if (keyWord == "") + separatorReached = true; + } - standardForm = - MWBase::Environment::get().getWindowManager()-> - getTranslationDataStorage().topicStandardForm(standardForm); + // sort by length to make sure longer topics are replaced first + std::sort(topics.begin(), topics.end(), sortByLength); - if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() ) + std::vector hypertext = MWDialogue::ParseHyperText(text); + + size_t historySize = 0; + if(mHistory->getClient()->getSubWidgetText() != NULL) + { + historySize = mHistory->getOnlyText().size(); + } + + std::string result; + size_t hypertextPos = 0; + for (size_t i = 0; i < hypertext.size(); ++i) + { + if (hypertext[i].mLink) { - result.append("#686EBA").append(hypertext[i].mText).append("#B29154"); + size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); + std::string standardForm = hypertext[i].mText; + for(; asterisk_count > 0; --asterisk_count) + standardForm.append("*"); - mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length(); - mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm); + standardForm = + MWBase::Environment::get().getWindowManager()-> + getTranslationDataStorage().topicStandardForm(standardForm); + + if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() ) + { + result.append("#686EBA").append(hypertext[i].mText).append("#B29154"); + + mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length(); + mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm); + } + else + result += hypertext[i].mText; } else - result += hypertext[i].mText; - } - else - { - if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { - for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { - addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154"); + for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + { + addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154"); + } } + + result += hypertext[i].mText; } - result += hypertext[i].mText; + hypertextPos += MyGUI::UString(hypertext[i].mText).length(); } - hypertextPos += MyGUI::UString(hypertext[i].mText).length(); + return result; } - return result; -} - -void DialogueWindow::addText(std::string text) -{ - mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); -} - -void DialogueWindow::addMessageBox(const std::string& text) -{ - mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); -} - -void DialogueWindow::addTitle(std::string text) -{ - // This is called from the dialogue manager, so text is - // case-smashed - thus we have to retrieve the correct case - // of the text through the topic list. - for (size_t i=0; igetItemCount(); ++i) + void DialogueWindow::addText(std::string text) { - std::string item = mTopicsList->getItemNameAt(i); - if (lower_string(item) == text) - text = item; + mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); } - mHistory->addDialogHeading(text); -} - -void DialogueWindow::askQuestion(std::string question) -{ - mHistory->addDialogText("#572D21"+question+"#B29154"+" "); -} - -void DialogueWindow::updateOptions() -{ - //Clear the list of topics - mTopicsList->clear(); - mHyperLinks.clear(); - mHistory->eraseText(0, mHistory->getTextLength()); - - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + void DialogueWindow::addMessageBox(const std::string& text) { - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); - mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); } -} -void DialogueWindow::goodbye() -{ - mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); - mTopicsList->setEnabled(false); - mEnabled = false; -} - -void DialogueWindow::onReferenceUnavailable() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); -} - -void DialogueWindow::onFrame() -{ - if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + void DialogueWindow::addTitle(std::string text) { - int disp = std::max(0, std::min(100, - MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) - + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(disp); - mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); + // This is called from the dialogue manager, so text is + // case-smashed - thus we have to retrieve the correct case + // of the text through the topic list. + for (size_t i=0; igetItemCount(); ++i) + { + std::string item = mTopicsList->getItemNameAt(i); + if (lower_string(item) == text) + text = item; + } + + mHistory->addDialogHeading(text); + } + + void DialogueWindow::askQuestion(std::string question) + { + mHistory->addDialogText("#572D21"+question+"#B29154"+" "); + } + + void DialogueWindow::updateOptions() + { + //Clear the list of topics + mTopicsList->clear(); + mHyperLinks.clear(); + mHistory->eraseText(0, mHistory->getTextLength()); + + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + } + } + + void DialogueWindow::goodbye() + { + mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); + mTopicsList->setEnabled(false); + mEnabled = false; + } + + void DialogueWindow::onReferenceUnavailable() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + } + + void DialogueWindow::onFrame() + { + if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + int disp = std::max(0, std::min(100, + MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(disp); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); + } } } diff --git a/apps/openmw/mwgui/dialoguehistory.cpp b/apps/openmw/mwgui/dialoguehistory.cpp index a122a7891..d99d55bc1 100644 --- a/apps/openmw/mwgui/dialoguehistory.cpp +++ b/apps/openmw/mwgui/dialoguehistory.cpp @@ -12,65 +12,67 @@ #include #include -using namespace MWGui; -using namespace Widgets; - -MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) +namespace MWGui { - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::TextIterator iterator(getCaption()); - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if (pos < _pos) - continue; - else if (pos == _pos) - break; - } - return colour; -} -MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) -{ - bool breakOnNext = false; - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::UString colour2 = colour; - MyGUI::TextIterator iterator(getCaption()); - MyGUI::TextIterator col_start = iterator; - while(iterator.moveNext()) + MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if(colour != colour2) + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::TextIterator iterator(getCaption()); + while(iterator.moveNext()) { - if(breakOnNext) + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if (pos < _pos) + continue; + else if (pos == _pos) + break; + } + return colour; + } + + MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) + { + bool breakOnNext = false; + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::UString colour2 = colour; + MyGUI::TextIterator iterator(getCaption()); + MyGUI::TextIterator col_start = iterator; + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if(colour != colour2) { - return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + if(breakOnNext) + { + return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + } + col_start = iterator; + colour2 = colour; + } + if (pos < _pos) + continue; + else if (pos == _pos) + { + breakOnNext = true; } - col_start = iterator; - colour2 = colour; - } - if (pos < _pos) - continue; - else if (pos == _pos) - { - breakOnNext = true; } + return ""; } - return ""; -} -void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) -{ - MyGUI::UString head("\n#D8C09A"); - head.append(parText); - head.append("#B29154\n"); - addText(head); -} + void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) + { + MyGUI::UString head("\n#D8C09A"); + head.append(parText); + head.append("#B29154\n"); + addText(head); + } + + void DialogueHistory::addDialogText(const MyGUI::UString& parText) + { + addText(parText); + addText("\n"); + } -void DialogueHistory::addDialogText(const MyGUI::UString& parText) -{ - addText(parText); - addText("\n"); } diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index b21b903bd..2d72f2174 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -9,8 +9,6 @@ #include #include -using namespace MWGui; - namespace { int convertFromHex(std::string hex) @@ -78,287 +76,292 @@ namespace } } -std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) +namespace MWGui { - using Ogre::UTFString; - std::vector result; - MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); - - boost::algorithm::replace_all(utf8Text, "\n", ""); - boost::algorithm::replace_all(utf8Text, "
", "\n"); - boost::algorithm::replace_all(utf8Text, "

", "\n\n"); - - UTFString text(utf8Text); - const int spacing = 48; - - const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); - const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); - const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); - - while (!text.empty()) + std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) { - // read in characters until we have exceeded the size, or run out of text - int currentWidth = 0; - int currentHeight = 0; + using Ogre::UTFString; + std::vector result; - size_t currentWordStart = 0; - size_t index = 0; - while (currentHeight <= height - spacing && index < text.size()) + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); + + boost::algorithm::replace_all(utf8Text, "\n", ""); + boost::algorithm::replace_all(utf8Text, "
", "\n"); + boost::algorithm::replace_all(utf8Text, "

", "\n\n"); + + UTFString text(utf8Text); + const int spacing = 48; + + const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); + const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); + const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); + + while (!text.empty()) { - const UTFString::unicode_char ch = text.getChar(index); - if (ch == LEFT_ANGLE) - { - const size_t tagStart = index + 1; - const size_t tagEnd = text.find('>', tagStart); - if (tagEnd == UTFString::npos) - throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); + // read in characters until we have exceeded the size, or run out of text + int currentWidth = 0; + int currentHeight = 0; - if (boost::algorithm::starts_with(tag, "IMG")) + size_t currentWordStart = 0; + size_t index = 0; + while (currentHeight <= height - spacing && index < text.size()) + { + const UTFString::unicode_char ch = text.getChar(index); + if (ch == LEFT_ANGLE) { - const int h = mHeight; - parseImage(tag, false); - currentHeight += (mHeight - h); - currentWidth = 0; - } - else if (boost::algorithm::starts_with(tag, "FONT")) - { - parseFont(tag); - if (currentWidth != 0) { - currentHeight += currentFontHeight(); - currentWidth = 0; - } - currentWidth = 0; - } - else if (boost::algorithm::starts_with(tag, "DIV")) - { - parseDiv(tag); - if (currentWidth != 0) { - currentHeight += currentFontHeight(); - currentWidth = 0; - } - } - index = tagEnd; - } - else if (ch == NEWLINE) - { - currentHeight += currentFontHeight(); - currentWidth = 0; - currentWordStart = index; - } - else if (ch == SPACE) - { - currentWidth += 3; // keep this in sync with the font's SpaceWidth property - currentWordStart = index; - } - else - { - currentWidth += widthForCharGlyph(ch); - } - - if (currentWidth > width) - { - currentHeight += currentFontHeight(); - currentWidth = 0; - // add size of the current word - UTFString word = text.substr(currentWordStart, index - currentWordStart); - for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) - currentWidth += widthForCharGlyph(it.getCharacter()); - } - index += UTFString::_utf16_char_length(ch); - } - const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) - ? currentWordStart : index; - - result.push_back(text.substr(0, pageEnd).asUTF8()); - text.erase(0, pageEnd); - } - - return result; -} - -float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const -{ - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); - return MyGUI::FontManager::getInstance().getByName(fontName) - ->getGlyphInfo(unicodeChar)->width; -} - -float BookTextParser::currentFontHeight() const -{ - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); - return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); -} - -MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) -{ - MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - text = Interpreter::fixDefinesBook(text, interpreterContext); - - mParent = parent; - mWidth = width; - mHeight = 0; - - assert(mParent); - while (mParent->getChildCount()) - { - MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); - } - - boost::algorithm::replace_all(text, "\n", ""); - boost::algorithm::replace_all(text, "
", "\n"); - boost::algorithm::replace_all(text, "

", "\n\n"); - - // remove leading newlines -// while (text[0] == '\n') -// text.erase(0); - - // remove trailing " - if (text[text.size()-1] == '\"') - text.erase(text.size()-1); - - parseSubText(text); - return MyGUI::IntSize(mWidth, mHeight); -} - -void BookTextParser::parseImage(std::string tag, bool createWidget) -{ - int src_start = tag.find("SRC=")+5; - std::string image = tag.substr(src_start, tag.find('"', src_start)-src_start); - - // fix texture extension to .dds - if (image.size() > 4) - { - image[image.size()-3] = 'd'; - image[image.size()-2] = 'd'; - image[image.size()-1] = 's'; - } - - int width_start = tag.find("WIDTH=")+7; - int width = boost::lexical_cast(tag.substr(width_start, tag.find('"', width_start)-width_start)); - - int height_start = tag.find("HEIGHT=")+8; - int height = boost::lexical_cast(tag.substr(height_start, tag.find('"', height_start)-height_start)); - - if (createWidget) - { - MyGUI::ImageBox* box = mParent->createWidget ("ImageBox", - MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top, - mParent->getName() + boost::lexical_cast(mParent->getChildCount())); - box->setImageTexture("bookart\\" + image); - box->setProperty("NeedMouse", "false"); - } - - mWidth = std::max(mWidth, width); - mHeight += height; -} - -void BookTextParser::parseDiv(std::string tag) -{ - if (tag.find("ALIGN=") == std::string::npos) - return; - - int align_start = tag.find("ALIGN=")+7; - std::string align = tag.substr(align_start, tag.find('"', align_start)-align_start); - if (align == "CENTER") - mTextStyle.mTextAlign = MyGUI::Align::HCenter; - else if (align == "LEFT") - mTextStyle.mTextAlign = MyGUI::Align::Left; -} - -void BookTextParser::parseFont(std::string tag) -{ - if (tag.find("COLOR=") != std::string::npos) - { - int color_start = tag.find("COLOR=")+7; - std::string color = tag.substr(color_start, tag.find('"', color_start)-color_start); - - mTextStyle.mColour = MyGUI::Colour( - convertFromHex(color.substr(0, 2))/255.0, - convertFromHex(color.substr(2, 2))/255.0, - convertFromHex(color.substr(4, 2))/255.0); - } - if (tag.find("FACE=") != std::string::npos) - { - int face_start = tag.find("FACE=")+6; - std::string face = tag.substr(face_start, tag.find('"', face_start)-face_start); - - if (face != "Magic Cards") - mTextStyle.mFont = face; - } - if (tag.find("SIZE=") != std::string::npos) - { - /// \todo - } -} - -void BookTextParser::parseSubText(std::string text) -{ - if (text[0] == '<') - { - const size_t tagStart = 1; - const size_t tagEnd = text.find('>', tagStart); - if (tagEnd == std::string::npos) - throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - const std::string tag = text.substr(tagStart, tagEnd - tagStart); - - if (boost::algorithm::starts_with(tag, "IMG")) - parseImage(tag); - if (boost::algorithm::starts_with(tag, "FONT")) - parseFont(tag); - if (boost::algorithm::starts_with(tag, "DOV")) - parseDiv(tag); - - text.erase(0, tagEnd + 1); - } - - size_t tagStart = std::string::npos; - std::string realText; // real text, without tags - for (size_t i = 0; i= text.size()) + const size_t tagStart = index + 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == UTFString::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - ++i; - c = text[i]; + const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); + + if (boost::algorithm::starts_with(tag, "IMG")) + { + const int h = mHeight; + parseImage(tag, false); + currentHeight += (mHeight - h); + currentWidth = 0; + } + else if (boost::algorithm::starts_with(tag, "FONT")) + { + parseFont(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } + currentWidth = 0; + } + else if (boost::algorithm::starts_with(tag, "DIV")) + { + parseDiv(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } + } + index = tagEnd; + } + else if (ch == NEWLINE) + { + currentHeight += currentFontHeight(); + currentWidth = 0; + currentWordStart = index; + } + else if (ch == SPACE) + { + currentWidth += 3; // keep this in sync with the font's SpaceWidth property + currentWordStart = index; + } + else + { + currentWidth += widthForCharGlyph(ch); + } + + if (currentWidth > width) + { + currentHeight += currentFontHeight(); + currentWidth = 0; + // add size of the current word + UTFString word = text.substr(currentWordStart, index - currentWordStart); + for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) + currentWidth += widthForCharGlyph(it.getCharacter()); + } + index += UTFString::_utf16_char_length(ch); + } + const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) + ? currentWordStart : index; + + result.push_back(text.substr(0, pageEnd).asUTF8()); + text.erase(0, pageEnd); + } + + return result; + } + + float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const + { + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName) + ->getGlyphInfo(unicodeChar)->width; + } + + float BookTextParser::currentFontHeight() const + { + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); + } + + MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) + { + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesBook(text, interpreterContext); + + mParent = parent; + mWidth = width; + mHeight = 0; + + assert(mParent); + while (mParent->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); + } + + boost::algorithm::replace_all(text, "\n", ""); + boost::algorithm::replace_all(text, "
", "\n"); + boost::algorithm::replace_all(text, "

", "\n\n"); + + // remove leading newlines + // while (text[0] == '\n') + // text.erase(0); + + // remove trailing " + if (text[text.size()-1] == '\"') + text.erase(text.size()-1); + + parseSubText(text); + return MyGUI::IntSize(mWidth, mHeight); + } + + void BookTextParser::parseImage(std::string tag, bool createWidget) + { + int src_start = tag.find("SRC=")+5; + std::string image = tag.substr(src_start, tag.find('"', src_start)-src_start); + + // fix texture extension to .dds + if (image.size() > 4) + { + image[image.size()-3] = 'd'; + image[image.size()-2] = 'd'; + image[image.size()-1] = 's'; + } + + int width_start = tag.find("WIDTH=")+7; + int width = boost::lexical_cast(tag.substr(width_start, tag.find('"', width_start)-width_start)); + + int height_start = tag.find("HEIGHT=")+8; + int height = boost::lexical_cast(tag.substr(height_start, tag.find('"', height_start)-height_start)); + + if (createWidget) + { + MyGUI::ImageBox* box = mParent->createWidget ("ImageBox", + MyGUI::IntCoord(0, mHeight, width, height), MyGUI::Align::Left | MyGUI::Align::Top, + mParent->getName() + boost::lexical_cast(mParent->getChildCount())); + box->setImageTexture("bookart\\" + image); + box->setProperty("NeedMouse", "false"); + } + + mWidth = std::max(mWidth, width); + mHeight += height; + } + + void BookTextParser::parseDiv(std::string tag) + { + if (tag.find("ALIGN=") == std::string::npos) + return; + + int align_start = tag.find("ALIGN=")+7; + std::string align = tag.substr(align_start, tag.find('"', align_start)-align_start); + if (align == "CENTER") + mTextStyle.mTextAlign = MyGUI::Align::HCenter; + else if (align == "LEFT") + mTextStyle.mTextAlign = MyGUI::Align::Left; + } + + void BookTextParser::parseFont(std::string tag) + { + if (tag.find("COLOR=") != std::string::npos) + { + int color_start = tag.find("COLOR=")+7; + std::string color = tag.substr(color_start, tag.find('"', color_start)-color_start); + + mTextStyle.mColour = MyGUI::Colour( + convertFromHex(color.substr(0, 2))/255.0, + convertFromHex(color.substr(2, 2))/255.0, + convertFromHex(color.substr(4, 2))/255.0); + } + if (tag.find("FACE=") != std::string::npos) + { + int face_start = tag.find("FACE=")+6; + std::string face = tag.substr(face_start, tag.find('"', face_start)-face_start); + + if (face != "Magic Cards") + mTextStyle.mFont = face; + } + if (tag.find("SIZE=") != std::string::npos) + { + /// \todo + } + } + + void BookTextParser::parseSubText(std::string text) + { + if (text[0] == '<') + { + const size_t tagStart = 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == std::string::npos) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart); + + if (boost::algorithm::starts_with(tag, "IMG")) + parseImage(tag); + if (boost::algorithm::starts_with(tag, "FONT")) + parseFont(tag); + if (boost::algorithm::starts_with(tag, "DOV")) + parseDiv(tag); + + text.erase(0, tagEnd + 1); + } + + size_t tagStart = std::string::npos; + std::string realText; // real text, without tags + for (size_t i = 0; i= text.size()) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + ++i; + c = text[i]; + } + continue; + } + else + { + tagStart = i; + break; } - continue; } else - { - tagStart = i; - break; - } + realText += c; + } + + MyGUI::EditBox* box = mParent->createWidget("NormalText", + MyGUI::IntCoord(0, mHeight, mWidth, 24), MyGUI::Align::Left | MyGUI::Align::Top, + mParent->getName() + boost::lexical_cast(mParent->getChildCount())); + box->setProperty("Static", "true"); + box->setProperty("MultiLine", "true"); + box->setProperty("WordWrap", "true"); + box->setProperty("NeedMouse", "false"); + box->setMaxTextLength(realText.size()); + box->setTextAlign(mTextStyle.mTextAlign); + box->setTextColour(mTextStyle.mColour); + box->setFontName(mTextStyle.mFont); + box->setCaption(realText); + box->setSize(box->getSize().width, box->getTextSize().height); + mHeight += box->getTextSize().height; + + if (tagStart != std::string::npos) + { + parseSubText(text.substr(tagStart, text.size())); } - else - realText += c; } - MyGUI::EditBox* box = mParent->createWidget("NormalText", - MyGUI::IntCoord(0, mHeight, mWidth, 24), MyGUI::Align::Left | MyGUI::Align::Top, - mParent->getName() + boost::lexical_cast(mParent->getChildCount())); - box->setProperty("Static", "true"); - box->setProperty("MultiLine", "true"); - box->setProperty("WordWrap", "true"); - box->setProperty("NeedMouse", "false"); - box->setMaxTextLength(realText.size()); - box->setTextAlign(mTextStyle.mTextAlign); - box->setTextColour(mTextStyle.mColour); - box->setFontName(mTextStyle.mFont); - box->setCaption(realText); - box->setSize(box->getSize().width, box->getTextSize().height); - mHeight += box->getTextSize().height; - - if (tagStart != std::string::npos) - { - parseSubText(text.substr(tagStart, text.size())); - } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 988bcfc24..59e00bf69 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -12,528 +12,531 @@ #include "console.hpp" #include "spellicons.hpp" -using namespace MWGui; - -HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) - : Layout("openmw_hud.layout") - , mHealth(NULL) - , mMagicka(NULL) - , mStamina(NULL) - , mWeapImage(NULL) - , mSpellImage(NULL) - , mWeapStatus(NULL) - , mSpellStatus(NULL) - , mEffectBox(NULL) - , mMinimap(NULL) - , mCompass(NULL) - , mCrosshair(NULL) - , mFpsBox(NULL) - , mFpsCounter(NULL) - , mTriangleCounter(NULL) - , mBatchCounter(NULL) - , mHealthManaStaminaBaseLeft(0) - , mWeapBoxBaseLeft(0) - , mSpellBoxBaseLeft(0) - , mEffectBoxBaseRight(0) - , mMinimapBoxBaseRight(0) - , mDragAndDrop(dragAndDrop) - , mCellNameTimer(0.0f) - , mCellNameBox(NULL) - , mMapVisible(true) - , mWeaponVisible(true) - , mSpellVisible(true) - , mWorldMouseOver(false) +namespace MWGui { - setCoord(0,0, width, height); - // Energy bars - getWidget(mHealthFrame, "HealthFrame"); - getWidget(mHealth, "Health"); - getWidget(mMagicka, "Magicka"); - getWidget(mStamina, "Stamina"); - mHealthManaStaminaBaseLeft = mHealthFrame->getLeft(); - - MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame; - getWidget(healthFrame, "HealthFrame"); - getWidget(magickaFrame, "MagickaFrame"); - getWidget(fatigueFrame, "FatigueFrame"); - healthFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); - magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); - fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); - - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - - // Item and spell images and status bars - getWidget(mWeapBox, "WeapBox"); - getWidget(mWeapImage, "WeapImage"); - getWidget(mWeapStatus, "WeapStatus"); - mWeapBoxBaseLeft = mWeapBox->getLeft(); - mWeapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); - - getWidget(mSpellBox, "SpellBox"); - getWidget(mSpellImage, "SpellImage"); - getWidget(mSpellStatus, "SpellStatus"); - mSpellBoxBaseLeft = mSpellBox->getLeft(); - mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); - - getWidget(mEffectBox, "EffectBox"); - mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); - - getWidget(mMinimapBox, "MiniMapBox"); - mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); - getWidget(mMinimap, "MiniMap"); - getWidget(mCompass, "Compass"); - getWidget(mMinimapButton, "MiniMapButton"); - mMinimapButton->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); - - getWidget(mCellNameBox, "CellName"); - getWidget(mWeaponSpellBox, "WeaponSpellName"); - - getWidget(mCrosshair, "Crosshair"); - - setFpsLevel(fpsLevel); - - getWidget(mTriangleCounter, "TriangleCounter"); - getWidget(mBatchCounter, "BatchCounter"); - - LocalMapBase::init(mMinimap, mCompass, this); - - mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); - mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); - mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); - - mSpellIcons = new SpellIcons(); -} - -HUD::~HUD() -{ - delete mSpellIcons; -} - -void HUD::setFpsLevel(int level) -{ - mFpsCounter = 0; - - MyGUI::Widget* fps; - getWidget(fps, "FPSBoxAdv"); - fps->setVisible(false); - getWidget(fps, "FPSBox"); - fps->setVisible(false); - - if (level == 2) + HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) + : Layout("openmw_hud.layout") + , mHealth(NULL) + , mMagicka(NULL) + , mStamina(NULL) + , mWeapImage(NULL) + , mSpellImage(NULL) + , mWeapStatus(NULL) + , mSpellStatus(NULL) + , mEffectBox(NULL) + , mMinimap(NULL) + , mCompass(NULL) + , mCrosshair(NULL) + , mFpsBox(NULL) + , mFpsCounter(NULL) + , mTriangleCounter(NULL) + , mBatchCounter(NULL) + , mHealthManaStaminaBaseLeft(0) + , mWeapBoxBaseLeft(0) + , mSpellBoxBaseLeft(0) + , mEffectBoxBaseRight(0) + , mMinimapBoxBaseRight(0) + , mDragAndDrop(dragAndDrop) + , mCellNameTimer(0.0f) + , mCellNameBox(NULL) + , mMapVisible(true) + , mWeaponVisible(true) + , mSpellVisible(true) + , mWorldMouseOver(false) { - getWidget(mFpsBox, "FPSBoxAdv"); - mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounterAdv"); + setCoord(0,0, width, height); + + // Energy bars + getWidget(mHealthFrame, "HealthFrame"); + getWidget(mHealth, "Health"); + getWidget(mMagicka, "Magicka"); + getWidget(mStamina, "Stamina"); + mHealthManaStaminaBaseLeft = mHealthFrame->getLeft(); + + MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame; + getWidget(healthFrame, "HealthFrame"); + getWidget(magickaFrame, "MagickaFrame"); + getWidget(fatigueFrame, "FatigueFrame"); + healthFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + magickaFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + fatigueFrame->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onHMSClicked); + + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // Item and spell images and status bars + getWidget(mWeapBox, "WeapBox"); + getWidget(mWeapImage, "WeapImage"); + getWidget(mWeapStatus, "WeapStatus"); + mWeapBoxBaseLeft = mWeapBox->getLeft(); + mWeapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); + + getWidget(mSpellBox, "SpellBox"); + getWidget(mSpellImage, "SpellImage"); + getWidget(mSpellStatus, "SpellStatus"); + mSpellBoxBaseLeft = mSpellBox->getLeft(); + mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); + + getWidget(mEffectBox, "EffectBox"); + mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); + + getWidget(mMinimapBox, "MiniMapBox"); + mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); + getWidget(mMinimap, "MiniMap"); + getWidget(mCompass, "Compass"); + getWidget(mMinimapButton, "MiniMapButton"); + mMinimapButton->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + + getWidget(mCellNameBox, "CellName"); + getWidget(mWeaponSpellBox, "WeaponSpellName"); + + getWidget(mCrosshair, "Crosshair"); + + setFpsLevel(fpsLevel); + + getWidget(mTriangleCounter, "TriangleCounter"); + getWidget(mBatchCounter, "BatchCounter"); + + LocalMapBase::init(mMinimap, mCompass, this); + + mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); + mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); + mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); + + mSpellIcons = new SpellIcons(); } - else if (level == 1) + + HUD::~HUD() { - getWidget(mFpsBox, "FPSBox"); - mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounter"); + delete mSpellIcons; } -} -void HUD::setFPS(float fps) -{ - if (mFpsCounter) - mFpsCounter->setCaption(boost::lexical_cast((int)fps)); -} - -void HUD::setTriangleCount(unsigned int count) -{ - mTriangleCounter->setCaption(boost::lexical_cast(count)); -} - -void HUD::setBatchCount(unsigned int count) -{ - mBatchCounter->setCaption(boost::lexical_cast(count)); -} - -void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = + void HUD::setFpsLevel(int level) { - "HBar", "MBar", "FBar", 0 - }; + mFpsCounter = 0; - for (int i=0; ids[i]; ++i) - if (ids[i]==id) + MyGUI::Widget* fps; + getWidget(fps, "FPSBoxAdv"); + fps->setVisible(false); + getWidget(fps, "FPSBox"); + fps->setVisible(false); + + if (level == 2) { - MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - switch (i) - { - case 0: - mHealth->setProgressRange (value.getModified()); - mHealth->setProgressPosition (value.getCurrent()); - getWidget(w, "HealthFrame"); - w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); - break; - case 1: - mMagicka->setProgressRange (value.getModified()); - mMagicka->setProgressPosition (value.getCurrent()); - getWidget(w, "MagickaFrame"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); - break; - case 2: - mStamina->setProgressRange (value.getModified()); - mStamina->setProgressPosition (value.getCurrent()); - getWidget(w, "FatigueFrame"); - w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); - break; - } + getWidget(mFpsBox, "FPSBoxAdv"); + mFpsBox->setVisible(true); + getWidget(mFpsCounter, "FPSCounterAdv"); + } + else if (level == 1) + { + getWidget(mFpsBox, "FPSBox"); + mFpsBox->setVisible(true); + getWidget(mFpsCounter, "FPSCounter"); } -} - -void HUD::onWorldClicked(MyGUI::Widget* _sender) -{ - if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ()) - return; - - if (mDragAndDrop->mIsOnDragAndDrop) - { - // drop item into the gameworld - MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - - MWBase::World* world = MWBase::Environment::get().getWorld(); - - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); - float mouseX = cursorPosition.left / float(viewSize.width); - float mouseY = cursorPosition.top / float(viewSize.height); - - int origCount = object.getRefData().getCount(); - object.getRefData().setCount(mDragAndDrop->mDraggedCount); - - if (world->canPlaceObject(mouseX, mouseY)) - world->placeObject(object, mouseX, mouseY); - else - world->dropObjectOnGround(world->getPlayer().getPlayer(), object); - - MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - - std::string sound = MWWorld::Class::get(object).getDownSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - // remove object from the container it was coming from - object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); - - mDragAndDrop->mIsOnDragAndDrop = false; - MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget = 0; - - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - mDragAndDrop->mDraggedFrom->drawItems(); - mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); } - else - { - GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) ) + void HUD::setFPS(float fps) + { + if (mFpsCounter) + mFpsCounter->setCaption(boost::lexical_cast((int)fps)); + } + + void HUD::setTriangleCount(unsigned int count) + { + mTriangleCounter->setCaption(boost::lexical_cast(count)); + } + + void HUD::setBatchCount(unsigned int count) + { + mBatchCounter->setCaption(boost::lexical_cast(count)); + } + + void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) + { + static const char *ids[] = + { + "HBar", "MBar", "FBar", 0 + }; + + for (int i=0; ids[i]; ++i) + if (ids[i]==id) + { + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + switch (i) + { + case 0: + mHealth->setProgressRange (value.getModified()); + mHealth->setProgressPosition (value.getCurrent()); + getWidget(w, "HealthFrame"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + break; + case 1: + mMagicka->setProgressRange (value.getModified()); + mMagicka->setProgressPosition (value.getCurrent()); + getWidget(w, "MagickaFrame"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + break; + case 2: + mStamina->setProgressRange (value.getModified()); + mStamina->setProgressPosition (value.getCurrent()); + getWidget(w, "FatigueFrame"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + break; + } + } + } + + void HUD::onWorldClicked(MyGUI::Widget* _sender) + { + if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ()) return; - MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); - - if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); - else if ((mode == GM_Container) || (mode == GM_Inventory)) + if (mDragAndDrop->mIsOnDragAndDrop) { - // pick up object - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object); - } - } -} + // drop item into the gameworld + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); -void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) -{ - if (mDragAndDrop->mIsOnDragAndDrop) - { - mWorldMouseOver = false; + MWBase::World* world = MWBase::Environment::get().getWorld(); - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); - float mouseX = cursorPosition.left / float(viewSize.width); - float mouseY = cursorPosition.top / float(viewSize.height); + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); - MWBase::World* world = MWBase::Environment::get().getWorld(); + int origCount = object.getRefData().getCount(); + object.getRefData().setCount(mDragAndDrop->mDraggedCount); - // if we can't drop the object at the wanted position, show the "drop on ground" cursor. - bool canDrop = world->canPlaceObject(mouseX, mouseY); + if (world->canPlaceObject(mouseX, mouseY)) + world->placeObject(object, mouseX, mouseY); + else + world->dropObjectOnGround(world->getPlayer().getPlayer(), object); - if (!canDrop) - MWBase::Environment::get().getWindowManager()->changePointer("drop_ground"); - else MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + // remove object from the container it was coming from + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget = 0; + + MWBase::Environment::get().getWindowManager()->setDragDrop(false); + mDragAndDrop->mDraggedFrom->drawItems(); + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); + } + else + { + GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + + if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) ) + return; + + MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); + + if (mode == GM_Console) + MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); + else if ((mode == GM_Container) || (mode == GM_Inventory)) + { + // pick up object + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object); + } + } } - else + + void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) + { + if (mDragAndDrop->mIsOnDragAndDrop) + { + mWorldMouseOver = false; + + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); + + MWBase::World* world = MWBase::Environment::get().getWorld(); + + // if we can't drop the object at the wanted position, show the "drop on ground" cursor. + bool canDrop = world->canPlaceObject(mouseX, mouseY); + + if (!canDrop) + MWBase::Environment::get().getWindowManager()->changePointer("drop_ground"); + else + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + + } + else + { + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + mWorldMouseOver = true; + } + } + + void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) { MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - mWorldMouseOver = true; - } -} - -void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) -{ - MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - mWorldMouseOver = false; -} - -void HUD::onHMSClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats); -} - -void HUD::onMapClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); -} - -void HUD::onWeaponClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory); -} - -void HUD::onMagicClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); -} - -void HUD::setCellName(const std::string& cellName) -{ - if (mCellName != cellName) - { - mCellNameTimer = 5.0f; - mCellName = cellName; - - mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}"); - mCellNameBox->setVisible(mMapVisible); - } -} - -void HUD::onFrame(float dt) -{ - mCellNameTimer -= dt; - mWeaponSpellTimer -= dt; - if (mCellNameTimer < 0) - mCellNameBox->setVisible(false); - if (mWeaponSpellTimer < 0) - mWeaponSpellBox->setVisible(false); -} - -void HUD::onResChange(int width, int height) -{ - setCoord(0, 0, width, height); -} - -void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) -{ - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - std::string spellName = spell->mName; - if (spellName != mSpellName && mSpellVisible) - { - mWeaponSpellTimer = 5.0f; - mSpellName = spellName; - mWeaponSpellBox->setCaption(mSpellName); - mWeaponSpellBox->setVisible(true); + mWorldMouseOver = false; } - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(successChancePercent); - - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - - mSpellBox->setUserString("ToolTipType", "Spell"); - mSpellBox->setUserString("Spell", spellId); - - // use the icon of the first effect - const ESM::MagicEffect* effect = - MWBase::Environment::get().getWorld()->getStore().get().find(spell->mEffects.mList.front().mEffectID); - - std::string icon = effect->mIcon; - int slashPos = icon.find("\\"); - icon.insert(slashPos+1, "b_"); - icon = std::string("icons\\") + icon; - Widgets::fixTexturePath(icon); - mSpellImage->setImageTexture(icon); -} - -void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) -{ - std::string itemName = MWWorld::Class::get(item).getName(item); - if (itemName != mSpellName && mSpellVisible) + void HUD::onHMSClicked(MyGUI::Widget* _sender) { - mWeaponSpellTimer = 5.0f; - mSpellName = itemName; - mWeaponSpellBox->setCaption(mSpellName); - mWeaponSpellBox->setVisible(true); + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats); } - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(chargePercent); - - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - - mSpellBox->setUserString("ToolTipType", "ItemPtr"); - mSpellBox->setUserData(item); - - mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = mSpellImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) - , MyGUI::Align::Stretch); - - std::string path = std::string("icons\\"); - path+=MWWorld::Class::get(item).getInventoryIcon(item); - Widgets::fixTexturePath(path); - itemBox->setImageTexture(path); - itemBox->setNeedMouseFocus(false); -} - -void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) -{ - std::string itemName = MWWorld::Class::get(item).getName(item); - if (itemName != mWeaponName && mWeaponVisible) + void HUD::onMapClicked(MyGUI::Widget* _sender) { - mWeaponSpellTimer = 5.0f; - mWeaponName = itemName; - mWeaponSpellBox->setCaption(mWeaponName); - mWeaponSpellBox->setVisible(true); + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); } - mWeapBox->setUserString("ToolTipType", "ItemPtr"); - mWeapBox->setUserData(item); - - mWeapStatus->setProgressRange(100); - mWeapStatus->setProgressPosition(durabilityPercent); - - if (mWeapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); - - std::string path = std::string("icons\\"); - path+=MWWorld::Class::get(item).getInventoryIcon(item); - Widgets::fixTexturePath(path); - - if (MWWorld::Class::get(item).getEnchantment(item) != "") + void HUD::onWeaponClicked(MyGUI::Widget* _sender) { - mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory); + } + + void HUD::onMagicClicked(MyGUI::Widget* _sender) + { + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Magic); + } + + void HUD::setCellName(const std::string& cellName) + { + if (mCellName != cellName) + { + mCellNameTimer = 5.0f; + mCellName = cellName; + + mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}"); + mCellNameBox->setVisible(mMapVisible); + } + } + + void HUD::onFrame(float dt) + { + mCellNameTimer -= dt; + mWeaponSpellTimer -= dt; + if (mCellNameTimer < 0) + mCellNameBox->setVisible(false); + if (mWeaponSpellTimer < 0) + mWeaponSpellBox->setVisible(false); + } + + void HUD::onResChange(int width, int height) + { + setCoord(0, 0, width, height); + } + + void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) + { + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + std::string spellName = spell->mName; + if (spellName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = spellName; + mWeaponSpellBox->setCaption(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(successChancePercent); + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + + mSpellBox->setUserString("ToolTipType", "Spell"); + mSpellBox->setUserString("Spell", spellId); + + // use the icon of the first effect + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld()->getStore().get().find(spell->mEffects.mList.front().mEffectID); + + std::string icon = effect->mIcon; + int slashPos = icon.find("\\"); + icon.insert(slashPos+1, "b_"); + icon = std::string("icons\\") + icon; + Widgets::fixTexturePath(icon); + mSpellImage->setImageTexture(icon); + } + + void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) + { + std::string itemName = MWWorld::Class::get(item).getName(item); + if (itemName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = itemName; + mWeaponSpellBox->setCaption(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(chargePercent); + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + + mSpellBox->setUserString("ToolTipType", "ItemPtr"); + mSpellBox->setUserData(item); + + mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = mSpellImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) , MyGUI::Align::Stretch); + + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(item).getInventoryIcon(item); + Widgets::fixTexturePath(path); itemBox->setImageTexture(path); itemBox->setNeedMouseFocus(false); } - else - mWeapImage->setImageTexture(path); -} -void HUD::unsetSelectedSpell() -{ - std::string spellName = "#{sNone}"; - if (spellName != mSpellName && mSpellVisible) + void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) { - mWeaponSpellTimer = 5.0f; - mSpellName = spellName; - mWeaponSpellBox->setCaptionWithReplacing(mSpellName); - mWeaponSpellBox->setVisible(true); + std::string itemName = MWWorld::Class::get(item).getName(item); + if (itemName != mWeaponName && mWeaponVisible) + { + mWeaponSpellTimer = 5.0f; + mWeaponName = itemName; + mWeaponSpellBox->setCaption(mWeaponName); + mWeaponSpellBox->setVisible(true); + } + + mWeapBox->setUserString("ToolTipType", "ItemPtr"); + mWeapBox->setUserData(item); + + mWeapStatus->setProgressRange(100); + mWeapStatus->setProgressPosition(durabilityPercent); + + if (mWeapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); + + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(item).getInventoryIcon(item); + Widgets::fixTexturePath(path); + + if (MWWorld::Class::get(item).getEnchantment(item) != "") + { + mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + , MyGUI::Align::Stretch); + itemBox->setImageTexture(path); + itemBox->setNeedMouseFocus(false); + } + else + mWeapImage->setImageTexture(path); } - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(0); - mSpellImage->setImageTexture(""); - mSpellBox->clearUserStrings(); -} - -void HUD::unsetSelectedWeapon() -{ - std::string itemName = "#{sSkillHandtohand}"; - if (itemName != mWeaponName && mWeaponVisible) + void HUD::unsetSelectedSpell() { - mWeaponSpellTimer = 5.0f; - mWeaponName = itemName; - mWeaponSpellBox->setCaptionWithReplacing(mWeaponName); - mWeaponSpellBox->setVisible(true); + std::string spellName = "#{sNone}"; + if (spellName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = spellName; + mWeaponSpellBox->setCaptionWithReplacing(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(0); + mSpellImage->setImageTexture(""); + mSpellBox->clearUserStrings(); + } + + void HUD::unsetSelectedWeapon() + { + std::string itemName = "#{sSkillHandtohand}"; + if (itemName != mWeaponName && mWeaponVisible) + { + mWeaponSpellTimer = 5.0f; + mWeaponName = itemName; + mWeaponSpellBox->setCaptionWithReplacing(mWeaponName); + mWeaponSpellBox->setVisible(true); + } + + if (mWeapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); + mWeapStatus->setProgressRange(100); + mWeapStatus->setProgressPosition(0); + mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); + mWeapBox->clearUserStrings(); + } + + void HUD::setCrosshairVisible(bool visible) + { + mCrosshair->setVisible (visible); + } + + void HUD::setHmsVisible(bool visible) + { + mHealth->setVisible(visible); + mMagicka->setVisible(visible); + mStamina->setVisible(visible); + updatePositions(); + } + + void HUD::setWeapVisible(bool visible) + { + mWeapBox->setVisible(visible); + updatePositions(); + } + + void HUD::setSpellVisible(bool visible) + { + mSpellBox->setVisible(visible); + updatePositions(); + } + + void HUD::setEffectVisible(bool visible) + { + mEffectBox->setVisible (visible); + updatePositions(); + } + + void HUD::setMinimapVisible(bool visible) + { + mMinimapBox->setVisible (visible); + updatePositions(); + } + + void HUD::updatePositions() + { + int weapDx = 0, spellDx = 0; + if (!mHealth->getVisible()) + spellDx = weapDx = mWeapBoxBaseLeft - mHealthManaStaminaBaseLeft; + + if (!mWeapBox->getVisible()) + spellDx += mSpellBoxBaseLeft - mWeapBoxBaseLeft; + + mWeaponVisible = mWeapBox->getVisible(); + mSpellVisible = mSpellBox->getVisible(); + if (!mWeaponVisible && !mSpellVisible) + mWeaponSpellBox->setVisible(false); + + mWeapBox->setPosition(mWeapBoxBaseLeft - weapDx, mWeapBox->getTop()); + mSpellBox->setPosition(mSpellBoxBaseLeft - spellDx, mSpellBox->getTop()); + + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // effect box can have variable width -> variable left coordinate + int effectsDx = 0; + if (!mMinimapBox->getVisible ()) + effectsDx = (viewSize.width - mMinimapBoxBaseRight) - (viewSize.width - mEffectBoxBaseRight); + + mMapVisible = mMinimapBox->getVisible (); + mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); + } + + void HUD::update() + { + mSpellIcons->updateWidgets(mEffectBox, true); } - if (mWeapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); - mWeapStatus->setProgressRange(100); - mWeapStatus->setProgressPosition(0); - mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); - mWeapBox->clearUserStrings(); -} - -void HUD::setCrosshairVisible(bool visible) -{ - mCrosshair->setVisible (visible); -} - -void HUD::setHmsVisible(bool visible) -{ - mHealth->setVisible(visible); - mMagicka->setVisible(visible); - mStamina->setVisible(visible); - updatePositions(); -} - -void HUD::setWeapVisible(bool visible) -{ - mWeapBox->setVisible(visible); - updatePositions(); -} - -void HUD::setSpellVisible(bool visible) -{ - mSpellBox->setVisible(visible); - updatePositions(); -} - -void HUD::setEffectVisible(bool visible) -{ - mEffectBox->setVisible (visible); - updatePositions(); -} - -void HUD::setMinimapVisible(bool visible) -{ - mMinimapBox->setVisible (visible); - updatePositions(); -} - -void HUD::updatePositions() -{ - int weapDx = 0, spellDx = 0; - if (!mHealth->getVisible()) - spellDx = weapDx = mWeapBoxBaseLeft - mHealthManaStaminaBaseLeft; - - if (!mWeapBox->getVisible()) - spellDx += mSpellBoxBaseLeft - mWeapBoxBaseLeft; - - mWeaponVisible = mWeapBox->getVisible(); - mSpellVisible = mSpellBox->getVisible(); - if (!mWeaponVisible && !mSpellVisible) - mWeaponSpellBox->setVisible(false); - - mWeapBox->setPosition(mWeapBoxBaseLeft - weapDx, mWeapBox->getTop()); - mSpellBox->setPosition(mSpellBoxBaseLeft - spellDx, mSpellBox->getTop()); - - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - - // effect box can have variable width -> variable left coordinate - int effectsDx = 0; - if (!mMinimapBox->getVisible ()) - effectsDx = (viewSize.width - mMinimapBoxBaseRight) - (viewSize.width - mEffectBoxBaseRight); - - mMapVisible = mMinimapBox->getVisible (); - mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); -} - -void HUD::update() -{ - mSpellIcons->updateWidgets(mEffectBox, true); } diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index c7b720730..8dda041ca 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -5,159 +5,165 @@ #include #include -using namespace MWGui; -using namespace MWGui::Widgets; - -MWList::MWList() : - mClient(0) - , mScrollView(0) - , mItemHeight(0) +namespace MWGui { -} -void MWList::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mClient, "Client"); - if (mClient == 0) - mClient = this; - - mScrollView = mClient->createWidgetReal( - "MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), - MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); -} - -void MWList::addItem(const std::string& name) -{ - mItems.push_back(name); -} - -void MWList::addSeparator() -{ - mItems.push_back(""); -} - -void MWList::adjustSize() -{ - redraw(); -} - -void MWList::redraw(bool scrollbarShown) -{ - const int _scrollBarWidth = 24; // fetch this from skin? - const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; - const int spacing = 3; - size_t scrollbarPosition = mScrollView->getScrollPosition(); - - while (mScrollView->getChildCount()) + namespace Widgets { - MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); - } - mItemHeight = 0; - int i=0; - for (std::vector::const_iterator it=mItems.begin(); - it!=mItems.end(); ++it) - { - if (*it != "") + MWList::MWList() : + mClient(0) + , mScrollView(0) + , mItemHeight(0) { - MyGUI::Button* button = mScrollView->createWidget( - "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), - MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); - button->setCaption((*it)); - button->getSubWidgetText()->setWordWrap(true); - button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); - button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); - - int height = button->getTextSize().height; - button->setSize(MyGUI::IntSize(button->getSize().width, height)); - button->setUserData(i); - - mItemHeight += height + spacing; } - else + + void MWList::initialiseOverride() { - MyGUI::ImageBox* separator = mScrollView->createWidget("MW_HLine", - MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth()-4, 18), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - separator->setNeedMouseFocus(false); + Base::initialiseOverride(); - mItemHeight += 18 + spacing; + assignWidget(mClient, "Client"); + if (mClient == 0) + mClient = this; + + mScrollView = mClient->createWidgetReal( + "MW_ScrollView", MyGUI::FloatCoord(0.0, 0.0, 1.0, 1.0), + MyGUI::Align::Top | MyGUI::Align::Left | MyGUI::Align::Stretch, getName() + "_ScrollView"); } - ++i; + + void MWList::addItem(const std::string& name) + { + mItems.push_back(name); + } + + void MWList::addSeparator() + { + mItems.push_back(""); + } + + void MWList::adjustSize() + { + redraw(); + } + + void MWList::redraw(bool scrollbarShown) + { + const int _scrollBarWidth = 24; // fetch this from skin? + const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; + const int spacing = 3; + size_t scrollbarPosition = mScrollView->getScrollPosition(); + + while (mScrollView->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); + } + + mItemHeight = 0; + int i=0; + for (std::vector::const_iterator it=mItems.begin(); + it!=mItems.end(); ++it) + { + if (*it != "") + { + MyGUI::Button* button = mScrollView->createWidget( + "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), + MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); + button->setCaption((*it)); + button->getSubWidgetText()->setWordWrap(true); + button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); + button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); + + int height = button->getTextSize().height; + button->setSize(MyGUI::IntSize(button->getSize().width, height)); + button->setUserData(i); + + mItemHeight += height + spacing; + } + else + { + MyGUI::ImageBox* separator = mScrollView->createWidget("MW_HLine", + MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth()-4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->setNeedMouseFocus(false); + + mItemHeight += 18 + spacing; + } + ++i; + } + mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); + + if (!scrollbarShown && mItemHeight > mClient->getSize().height) + redraw(true); + + size_t scrollbarRange = mScrollView->getScrollRange(); + if(scrollbarPosition > scrollbarRange) + scrollbarPosition = scrollbarRange; + mScrollView->setScrollPosition(scrollbarPosition); + } + + bool MWList::hasItem(const std::string& name) + { + return (std::find(mItems.begin(), mItems.end(), name) != mItems.end()); + } + + unsigned int MWList::getItemCount() + { + return mItems.size(); + } + + std::string MWList::getItemNameAt(unsigned int at) + { + assert(at < mItems.size() && "List item out of bounds"); + return mItems[at]; + } + + void MWList::removeItem(const std::string& name) + { + assert( std::find(mItems.begin(), mItems.end(), name) != mItems.end() ); + mItems.erase( std::find(mItems.begin(), mItems.end(), name) ); + } + + void MWList::clear() + { + mItems.clear(); + } + + void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + //NB view offset is negative + if (mScrollView->getViewOffset().top + _rel*0.3 > 0) + mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); + } + + void MWList::onItemSelected(MyGUI::Widget* _sender) + { + std::string name = static_cast(_sender)->getCaption(); + int id = *_sender->getUserData(); + eventItemSelected(name, id); + eventWidgetSelected(_sender); + } + + MyGUI::Widget* MWList::getItemWidget(const std::string& name) + { + return mScrollView->findWidget (getName() + "_item_" + name); + } + + size_t MWScrollView::getScrollPosition() + { + return getVScroll()->getScrollPosition(); + } + + void MWScrollView::setScrollPosition(size_t position) + { + getVScroll()->setScrollPosition(position); + } + size_t MWScrollView::getScrollRange() + { + return getVScroll()->getScrollRange(); + } + } - mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); - - if (!scrollbarShown && mItemHeight > mClient->getSize().height) - redraw(true); - - size_t scrollbarRange = mScrollView->getScrollRange(); - if(scrollbarPosition > scrollbarRange) - scrollbarPosition = scrollbarRange; - mScrollView->setScrollPosition(scrollbarPosition); -} - -bool MWList::hasItem(const std::string& name) -{ - return (std::find(mItems.begin(), mItems.end(), name) != mItems.end()); -} - -unsigned int MWList::getItemCount() -{ - return mItems.size(); -} - -std::string MWList::getItemNameAt(unsigned int at) -{ - assert(at < mItems.size() && "List item out of bounds"); - return mItems[at]; -} - -void MWList::removeItem(const std::string& name) -{ - assert( std::find(mItems.begin(), mItems.end(), name) != mItems.end() ); - mItems.erase( std::find(mItems.begin(), mItems.end(), name) ); -} - -void MWList::clear() -{ - mItems.clear(); -} - -void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - //NB view offset is negative - if (mScrollView->getViewOffset().top + _rel*0.3 > 0) - mScrollView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mScrollView->setViewOffset(MyGUI::IntPoint(0, mScrollView->getViewOffset().top + _rel*0.3)); -} - -void MWList::onItemSelected(MyGUI::Widget* _sender) -{ - std::string name = static_cast(_sender)->getCaption(); - int id = *_sender->getUserData(); - eventItemSelected(name, id); - eventWidgetSelected(_sender); -} - -MyGUI::Widget* MWList::getItemWidget(const std::string& name) -{ - return mScrollView->findWidget (getName() + "_item_" + name); -} - -size_t MWScrollView::getScrollPosition() -{ - return getVScroll()->getScrollPosition(); -} - -void MWScrollView::setScrollPosition(size_t position) -{ - getVScroll()->setScrollPosition(position); -} -size_t MWScrollView::getScrollRange() -{ - return getVScroll()->getScrollRange(); } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 1ac1c2448..4a78238ce 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -13,430 +13,433 @@ #include "widgets.hpp" -using namespace MWGui; - -LocalMapBase::LocalMapBase() - : mCurX(0) - , mCurY(0) - , mInterior(false) - , mFogOfWar(true) - , mLocalMap(NULL) - , mMapDragAndDrop(false) - , mPrefix() - , mChanged(true) - , mLayout(NULL) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) - , mLastDirectionX(0.0f) - , mLastDirectionY(0.0f) - , mCompass(NULL) +namespace MWGui { -} -void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) -{ - mLocalMap = widget; - mLayout = layout; - mMapDragAndDrop = mapDragAndDrop; - mCompass = compass; - - // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each - const int widgetSize = 512; - for (int mx=0; mx<3; ++mx) + LocalMapBase::LocalMapBase() + : mCurX(0) + , mCurY(0) + , mInterior(false) + , mFogOfWar(true) + , mLocalMap(NULL) + , mMapDragAndDrop(false) + , mPrefix() + , mChanged(true) + , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) + , mCompass(NULL) { - for (int my=0; my<3; ++my) + } + + void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) + { + mLocalMap = widget; + mLayout = layout; + mMapDragAndDrop = mapDragAndDrop; + mCompass = compass; + + // create 3x3 map widgets, 512x512 each, holding a 1024x1024 texture each + const int widgetSize = 512; + for (int mx=0; mx<3; ++mx) { - MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", - MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); - - MyGUI::ImageBox* fog = map->createWidget("ImageBox", - MyGUI::IntCoord(0, 0, widgetSize, widgetSize), - MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); - - if (!mMapDragAndDrop) + for (int my=0; my<3; ++my) { - map->setNeedMouseFocus(false); - fog->setNeedMouseFocus(false); - } + MyGUI::ImageBox* map = mLocalMap->createWidget("ImageBox", + MyGUI::IntCoord(mx*widgetSize, my*widgetSize, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my)); - mMapWidgets.push_back(map); - mFogWidgets.push_back(fog); - } - } -} + MyGUI::ImageBox* fog = map->createWidget("ImageBox", + MyGUI::IntCoord(0, 0, widgetSize, widgetSize), + MyGUI::Align::Top | MyGUI::Align::Left, "Map_" + boost::lexical_cast(mx) + "_" + boost::lexical_cast(my) + "_fog"); -void LocalMapBase::setCellPrefix(const std::string& prefix) -{ - mPrefix = prefix; - mChanged = true; -} - -void LocalMapBase::toggleFogOfWar() -{ - mFogOfWar = !mFogOfWar; - applyFogOfWar(); -} - -void LocalMapBase::applyFogOfWar() -{ - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (-1*(my-1))); - MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) - : ""); - } - } - notifyMapChanged (); -} - -void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::setActiveCell(const int x, const int y, bool interior) -{ - if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell - - // clear all previous markers - for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) - { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") - { - MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); - } - } - - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - // map - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (-1*(my-1))); - - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - - MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; - - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); - else - box->setImageTexture("black.png"); - - - // door markers - - // interior map only consists of one cell, so handle the markers only once - if (interior && (mx != 2 || my != 2)) - continue; - - MWWorld::CellStore* cell; - if (interior) - cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); - else - cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); - - std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); - - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) - { - MWBase::World::DoorMarker marker = *it; - - // convert world coordinates to normalized cell coordinates - MyGUI::IntCoord widgetCoord; - float nX,nY; - int cellDx, cellDy; - if (!interior) + if (!mMapDragAndDrop) { - const int cellSize = 8192; - - nX = (marker.x - cellSize * (x+mx-1)) / cellSize; - nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + map->setNeedMouseFocus(false); + fog->setNeedMouseFocus(false); } + + mMapWidgets.push_back(map); + mFogWidgets.push_back(fog); + } + } + } + + void LocalMapBase::setCellPrefix(const std::string& prefix) + { + mPrefix = prefix; + mChanged = true; + } + + void LocalMapBase::toggleFogOfWar() + { + mFogOfWar = !mFogOfWar; + applyFogOfWar(); + } + + void LocalMapBase::applyFogOfWar() + { + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" + + boost::lexical_cast(mCurY + (-1*(my-1))); + MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; + fog->setImageTexture(mFogOfWar ? + ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" + : "black.png" ) + : ""); + } + } + notifyMapChanged (); + } + + void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) + { + applyFogOfWar (); + } + + void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) + { + applyFogOfWar (); + } + + void LocalMapBase::setActiveCell(const int x, const int y, bool interior) + { + if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell + + // clear all previous markers + for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) + { + if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + { + MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); + } + } + + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + // map + std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + + boost::lexical_cast(y + (-1*(my-1))); + + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + MyGUI::ImageBox* box = mMapWidgets[my + 3*mx]; + + if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) + box->setImageTexture(image); else - { - Ogre::Vector2 position (marker.x, marker.y); - MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + box->setImageTexture("black.png"); - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + + // door markers + + // interior map only consists of one cell, so handle the markers only once + if (interior && (mx != 2 || my != 2)) + continue; + + MWWorld::CellStore* cell; + if (interior) + cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); + else + cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); + + std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); + + for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + { + MWBase::World::DoorMarker marker = *it; + + // convert world coordinates to normalized cell coordinates + MyGUI::IntCoord widgetCoord; + float nX,nY; + int cellDx, cellDy; + if (!interior) + { + const int cellSize = 8192; + + nX = (marker.x - cellSize * (x+mx-1)) / cellSize; + nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + } + else + { + Ogre::Vector2 position (marker.x, marker.y); + MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + } + + static int counter = 0; + ++counter; + MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); + markerWidget->setUserString("IsMarker", "true"); + markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); + markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); + + MarkerPosition markerPos; + markerPos.interior = interior; + markerPos.cellX = interior ? cellDx : x + mx - 1; + markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); + markerPos.nX = nX; + markerPos.nY = nY; + + markerWidget->setUserData(markerPos); } - static int counter = 0; - ++counter; - MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", marker.name); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); - markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); - MarkerPosition markerPos; - markerPos.interior = interior; - markerPos.cellX = interior ? cellDx : x + mx - 1; - markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); - markerPos.nX = nX; - markerPos.nY = nY; - - markerWidget->setUserData(markerPos); } - - } - } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; + mInterior = interior; + mCurX = x; + mCurY = y; + mChanged = false; - // fog of war - applyFogOfWar(); + // fog of war + applyFogOfWar(); - // set the compass texture again, because MyGUI determines sorting of ImageBox widgets - // based on the last setImageTexture call - std::string tex = "textures\\compass.dds"; - mCompass->setImageTexture(""); - mCompass->setImageTexture(tex); -} - - -void LocalMapBase::setPlayerPos(const float x, const float y) -{ - if (x == mLastPositionX && y == mLastPositionY) - return; - - notifyPlayerUpdate (); - - MyGUI::IntSize size = mLocalMap->getCanvasSize(); - MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); - MyGUI::IntCoord viewsize = mLocalMap->getCoord(); - MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); - mLocalMap->setViewOffset(pos); - - mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); - mLastPositionX = x; - mLastPositionY = y; -} - -void LocalMapBase::setPlayerDir(const float x, const float y) -{ - if (x == mLastDirectionX && y == mLastDirectionY) - return; - - notifyPlayerUpdate (); - - MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(x,y); - rotatingSubskin->setAngle(angle); - - mLastDirectionX = x; - mLastDirectionY = y; -} - -// ------------------------------------------------------------------------------------------ - -MapWindow::MapWindow(const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout") - , mGlobal(false) -{ - setCoord(500,0,320,300); - - mGlobalMapRender = new MWRender::GlobalMap(cacheDir); - mGlobalMapRender->render(); - - getWidget(mLocalMap, "LocalMap"); - getWidget(mGlobalMap, "GlobalMap"); - getWidget(mGlobalMapImage, "GlobalMapImage"); - getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); - getWidget(mPlayerArrowLocal, "CompassLocal"); - getWidget(mPlayerArrowGlobal, "CompassGlobal"); - - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); - - mGlobalMap->setVisible (false); - - getWidget(mButton, "WorldButton"); - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing("#{sWorld}"); - - getWidget(mEventBoxGlobal, "EventBoxGlobal"); - mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - getWidget(mEventBoxLocal, "EventBoxLocal"); - mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - - LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); -} - -MapWindow::~MapWindow() -{ - delete mGlobalMapRender; -} - -void MapWindow::setCellName(const std::string& cellName) -{ - setTitle("#{sCell=" + cellName + "}"); -} - -void MapWindow::addVisitedLocation(const std::string& name, int x, int y) -{ - float worldX, worldY; - mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); - - MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+6, - worldY * mGlobalMapRender->getHeight()+6, - 12, 12); - - - static int _counter=0; - MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); - ++_counter; - - markerWidget = mEventBoxGlobal->createWidget("", - widgetCoord, MyGUI::Align::Default); - markerWidget->setNeedMouseFocus (true); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); -} - -void MapWindow::cellExplored(int x, int y) -{ - mGlobalMapRender->exploreCell(x,y); -} - -void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - - MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - - if (!mGlobal) - mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); - else - mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); - - - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) -{ - mGlobal = !mGlobal; - mGlobalMap->setVisible(mGlobal); - mLocalMap->setVisible(!mGlobal); - - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); - - if (mGlobal) - globalMapUpdatePlayer (); -} - -void MapWindow::onPinToggled() -{ - MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); -} - -void MapWindow::open() -{ - mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - - for (unsigned int i=0; igetChildCount (); ++i) - { - if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") - mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + // set the compass texture again, because MyGUI determines sorting of ImageBox widgets + // based on the last setImageTexture call + std::string tex = "textures\\compass.dds"; + mCompass->setImageTexture(""); + mCompass->setImageTexture(tex); } - globalMapUpdatePlayer(); - mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); -} - -void MapWindow::globalMapUpdatePlayer () -{ - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); - Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - - // for interiors, we have no choice other than using the last position & direction. - /// \todo save this last position in the savegame? - if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + void LocalMapBase::setPlayerPos(const float x, const float y) { - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + if (x == mLastPositionX && y == mLastPositionY) + return; - MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + notifyPlayerUpdate (); + + MyGUI::IntSize size = mLocalMap->getCanvasSize(); + MyGUI::IntPoint middle = MyGUI::IntPoint((1/3.f + x/3.f)*size.width,(1/3.f + y/3.f)*size.height); + MyGUI::IntCoord viewsize = mLocalMap->getCoord(); + MyGUI::IntPoint pos(0.5*viewsize.width - middle.left, 0.5*viewsize.height - middle.top); + mLocalMap->setViewOffset(pos); + + mCompass->setPosition(MyGUI::IntPoint(512+x*512-16, 512+y*512-16)); + mLastPositionX = x; + mLastPositionY = y; + } + + void LocalMapBase::setPlayerDir(const float x, const float y) + { + if (x == mLastDirectionX && y == mLastDirectionY) + return; + + notifyPlayerUpdate (); + + MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(dir.x, dir.y); + float angle = std::atan2(x,y); rotatingSubskin->setAngle(angle); - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); - mGlobalMap->setViewOffset(viewoffs); + mLastDirectionX = x; + mLastDirectionY = y; } -} -void MapWindow::notifyPlayerUpdate () -{ - globalMapUpdatePlayer (); -} + // ------------------------------------------------------------------------------------------ -void MapWindow::notifyMapChanged () -{ - // workaround to prevent the map from drawing on top of the button - MyGUI::IntCoord oldCoord = mButton->getCoord (); - MyGUI::Gui::getInstance().destroyWidget (mButton); - mButton = mMainWidget->createWidget("MW_Button", - oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); - mButton->setProperty ("ExpandDirection", "Left"); + MapWindow::MapWindow(const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout") + , mGlobal(false) + { + setCoord(500,0,320,300); + + mGlobalMapRender = new MWRender::GlobalMap(cacheDir); + mGlobalMapRender->render(); + + getWidget(mLocalMap, "LocalMap"); + getWidget(mGlobalMap, "GlobalMap"); + getWidget(mGlobalMapImage, "GlobalMapImage"); + getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); + getWidget(mPlayerArrowLocal, "CompassLocal"); + getWidget(mPlayerArrowGlobal, "CompassGlobal"); + + mGlobalMapImage->setImageTexture("GlobalMap.png"); + mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + + mGlobalMap->setVisible (false); + + getWidget(mButton, "WorldButton"); + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing("#{sWorld}"); + + getWidget(mEventBoxGlobal, "EventBoxGlobal"); + mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + getWidget(mEventBoxLocal, "EventBoxLocal"); + mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); + } + + MapWindow::~MapWindow() + { + delete mGlobalMapRender; + } + + void MapWindow::setCellName(const std::string& cellName) + { + setTitle("#{sCell=" + cellName + "}"); + } + + void MapWindow::addVisitedLocation(const std::string& name, int x, int y) + { + float worldX, worldY; + mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); + + MyGUI::IntCoord widgetCoord( + worldX * mGlobalMapRender->getWidth()+6, + worldY * mGlobalMapRender->getHeight()+6, + 12, 12); + + + static int _counter=0; + MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + ++_counter; + + markerWidget = mEventBoxGlobal->createWidget("", + widgetCoord, MyGUI::Align::Default); + markerWidget->setNeedMouseFocus (true); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + } + + void MapWindow::cellExplored(int x, int y) + { + mGlobalMapRender->exploreCell(x,y); + } + + void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + if (_id!=MyGUI::MouseButton::Left) return; + mLastDragPos = MyGUI::IntPoint(_left, _top); + } + + void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + if (_id!=MyGUI::MouseButton::Left) return; + + MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; + + if (!mGlobal) + mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + else + mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); + + + mLastDragPos = MyGUI::IntPoint(_left, _top); + } + + void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) + { + mGlobal = !mGlobal; + mGlobalMap->setVisible(mGlobal); + mLocalMap->setVisible(!mGlobal); + + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + + if (mGlobal) + globalMapUpdatePlayer (); + } + + void MapWindow::onPinToggled() + { + MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); + } + + void MapWindow::open() + { + mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + + for (unsigned int i=0; igetChildCount (); ++i) + { + if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") + mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + } + + globalMapUpdatePlayer(); + + mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); + } + + void MapWindow::globalMapUpdatePlayer () + { + Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); + Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); + + float worldX, worldY; + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); + worldX *= mGlobalMapRender->getWidth(); + worldY *= mGlobalMapRender->getHeight(); + + + // for interiors, we have no choice other than using the last position & direction. + /// \todo save this last position in the savegame? + if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + { + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + + MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(dir.x, dir.y); + rotatingSubskin->setAngle(angle); + + // set the view offset so that player is in the center + MyGUI::IntSize viewsize = mGlobalMap->getSize(); + MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); + mGlobalMap->setViewOffset(viewoffs); + } + } + + void MapWindow::notifyPlayerUpdate () + { + globalMapUpdatePlayer (); + } + + void MapWindow::notifyMapChanged () + { + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + } - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 8e53380bd..876fb3522 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -5,411 +5,414 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" -using namespace MWGui; - -MessageBoxManager::MessageBoxManager () +namespace MWGui { - // defines - mMessageBoxSpeed = 0.1; - mInterMessageBoxe = NULL; -} -void MessageBoxManager::onFrame (float frameDuration) -{ - std::vector::iterator it; - for(it = mTimers.begin(); it != mTimers.end();) + MessageBoxManager::MessageBoxManager () { - // if this messagebox is already deleted, remove the timer and move on - if (std::find(mMessageBoxes.begin(), mMessageBoxes.end(), it->messageBox) == mMessageBoxes.end()) - { - it = mTimers.erase(it); - continue; - } + // defines + mMessageBoxSpeed = 0.1; + mInterMessageBoxe = NULL; + } - it->current += frameDuration; - if(it->current >= it->max) + void MessageBoxManager::onFrame (float frameDuration) + { + std::vector::iterator it; + for(it = mTimers.begin(); it != mTimers.end();) { - it->messageBox->mMarkedToDelete = true; - - if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one + // if this messagebox is already deleted, remove the timer and move on + if (std::find(mMessageBoxes.begin(), mMessageBoxes.end(), it->messageBox) == mMessageBoxes.end()) { - // collect all with mMarkedToDelete and delete them. - // and place the other messageboxes on the right position - int height = 0; - std::vector::iterator it2 = mMessageBoxes.begin(); - while(it2 != mMessageBoxes.end()) + it = mTimers.erase(it); + continue; + } + + it->current += frameDuration; + if(it->current >= it->max) + { + it->messageBox->mMarkedToDelete = true; + + if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one { - if((*it2)->mMarkedToDelete) + // collect all with mMarkedToDelete and delete them. + // and place the other messageboxes on the right position + int height = 0; + std::vector::iterator it2 = mMessageBoxes.begin(); + while(it2 != mMessageBoxes.end()) { - delete (*it2); - it2 = mMessageBoxes.erase(it2); - } - else { - (*it2)->update(height); - height += (*it2)->getHeight(); - it2++; + if((*it2)->mMarkedToDelete) + { + delete (*it2); + it2 = mMessageBoxes.erase(it2); + } + else { + (*it2)->update(height); + height += (*it2)->getHeight(); + it2++; + } } } + it = mTimers.erase(it); + } + else + { + it++; + } + } + + if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; + MWBase::Environment::get().getInputManager()->changeInputMode( + MWBase::Environment::get().getWindowManager()->isGuiMode()); + } + } + + void MessageBoxManager::createMessageBox (const std::string& message) + { + MessageBox *box = new MessageBox(*this, message); + + removeMessageBox(message.length()*mMessageBoxSpeed, box); + + mMessageBoxes.push_back(box); + std::vector::iterator it; + + if(mMessageBoxes.size() > 3) { + delete *mMessageBoxes.begin(); + mMessageBoxes.erase(mMessageBoxes.begin()); + } + + int height = 0; + for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + { + (*it)->update(height); + height += (*it)->getHeight(); + } + } + + bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) + { + if(mInterMessageBoxe != NULL) { + throw std::runtime_error("There is a message box already"); + } + + mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); + + return true; + } + + bool MessageBoxManager::isInteractiveMessageBox () + { + return mInterMessageBoxe != NULL; + } + + void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox) + { + MessageBoxManagerTimer timer; + timer.current = 0; + timer.max = time; + timer.messageBox = msgbox; + + mTimers.insert(mTimers.end(), timer); + } + + bool MessageBoxManager::removeMessageBox (MessageBox *msgbox) + { + std::vector::iterator it; + for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + { + if((*it) == msgbox) + { + delete (*it); + mMessageBoxes.erase(it); + return true; + } + } + return false; + } + + void MessageBoxManager::setMessageBoxSpeed (int speed) + { + mMessageBoxSpeed = speed; + } + + void MessageBoxManager::enterPressed () + { + if(mInterMessageBoxe != NULL) + mInterMessageBoxe->enterPressed(); + } + + int MessageBoxManager::readPressedButton () + { + if(mInterMessageBoxe != NULL) + { + return mInterMessageBoxe->readPressedButton(); + } + return -1; + } + + + + + MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) + : Layout("openmw_messagebox.layout") + , mMessageBoxManager(parMessageBoxManager) + , mMessage(message) + { + // defines + mFixedWidth = 300; + mBottomPadding = 20; + mNextBoxPadding = 20; + mMarkedToDelete = false; + + getWidget(mMessageWidget, "message"); + + mMessageWidget->setOverflowToTheLeft(true); + mMessageWidget->setCaptionWithReplacing(mMessage); + + MyGUI::IntSize size; + size.width = mFixedWidth; + size.height = 100; // dummy + + MyGUI::IntCoord coord; + coord.left = 10; // dummy + coord.top = 10; // dummy + + mMessageWidget->setSize(size); + + MyGUI::IntSize textSize = mMessageWidget->getTextSize(); + + size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box + + mMainWidget->setSize(size); + size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0") + mMessageWidget->setSize(size); + } + + void MessageBox::update (int height) + { + MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntCoord coord; + coord.left = (gameWindowSize.width - mFixedWidth)/2; + coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); + + MyGUI::IntSize size; + size.width = mFixedWidth; + size.height = mHeight; + + mMainWidget->setCoord(coord); + mMainWidget->setSize(size); + mMainWidget->setVisible(true); + } + + int MessageBox::getHeight () + { + return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox + } + + + + InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) + : WindowModal("openmw_interactive_messagebox.layout") + , mMessageBoxManager(parMessageBoxManager) + , mButtonPressed(-1) + { + WindowModal::open(); + + int fixedWidth = 500; + int textPadding = 10; // padding between text-widget and main-widget + int textButtonPadding = 20; // padding between the text-widget und the button-widget + int buttonLeftPadding = 10; // padding between the buttons if horizontal + int buttonTopPadding = 5; // ^-- if vertical + int buttonPadding = 5; // padding between button label and button itself + int buttonMainPadding = 10; // padding between buttons and bottom of the main widget + + mMarkedToDelete = false; + + + getWidget(mMessageWidget, "message"); + getWidget(mButtonsWidget, "buttons"); + + mMessageWidget->setOverflowToTheLeft(true); + mMessageWidget->setCaptionWithReplacing(message); + + MyGUI::IntSize textSize = mMessageWidget->getTextSize(); + + MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + + int biggestButtonWidth = 0; + int buttonWidth = 0; + int buttonsWidth = 0; + int buttonHeight = 0; + MyGUI::IntCoord dummyCoord(0, 0, 0, 0); + + std::vector::const_iterator it; + for(it = buttons.begin(); it != buttons.end(); ++it) + { + MyGUI::Button* button = mButtonsWidget->createWidget( + MyGUI::WidgetStyle::Child, + std::string("MW_Button"), + dummyCoord, + MyGUI::Align::Default); + button->setCaptionWithReplacing(*it); + + button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); + + mButtons.push_back(button); + + buttonWidth = button->getTextSize().width + 2*buttonPadding + buttonLeftPadding; + buttonsWidth += buttonWidth; + buttonHeight = button->getTextSize().height + 2*buttonPadding + buttonTopPadding; + + if(buttonWidth > biggestButtonWidth) + { + biggestButtonWidth = buttonWidth; + } + } + buttonsWidth += buttonLeftPadding; + + MyGUI::IntSize mainWidgetSize; + if(buttonsWidth < fixedWidth) + { + // on one line + if(textSize.width + 2*textPadding < buttonsWidth) + { + mainWidgetSize.width = buttonsWidth; + } + else + { + mainWidgetSize.width = textSize.width + 3*textPadding; + } + mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; + + MyGUI::IntCoord absCoord; + absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + mMainWidget->setCoord(absCoord); + mMainWidget->setSize(mainWidgetSize); + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + mMessageWidget->setCoord(messageWidgetCoord); + + mMessageWidget->setSize(textSize); + + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonCord.left = left; + buttonCord.top = textSize.height + textButtonPadding; + + buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; + buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + left += buttonSize.width + buttonLeftPadding; } - it = mTimers.erase(it); } else { - it++; + // among each other + if(biggestButtonWidth > textSize.width) { + mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; + } + else { + mainWidgetSize.width = textSize.width + 3*textPadding; + } + mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; + + mMainWidget->setSize(mainWidgetSize); + + MyGUI::IntCoord absCoord; + absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + mMainWidget->setCoord(absCoord); + mMainWidget->setSize(mainWidgetSize); + + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + mMessageWidget->setCoord(messageWidgetCoord); + + mMessageWidget->setSize(textSize); + + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + + int top = textButtonPadding + buttonTopPadding + textSize.height; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; + buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; + + buttonCord.top = top; + buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + top += buttonSize.height + 2*buttonTopPadding; + } + } } - if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { - delete mInterMessageBoxe; - mInterMessageBoxe = NULL; - MWBase::Environment::get().getInputManager()->changeInputMode( - MWBase::Environment::get().getWindowManager()->isGuiMode()); - } -} - -void MessageBoxManager::createMessageBox (const std::string& message) -{ - MessageBox *box = new MessageBox(*this, message); - - removeMessageBox(message.length()*mMessageBoxSpeed, box); - - mMessageBoxes.push_back(box); - std::vector::iterator it; - - if(mMessageBoxes.size() > 3) { - delete *mMessageBoxes.begin(); - mMessageBoxes.erase(mMessageBoxes.begin()); - } - - int height = 0; - for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + void InteractiveMessageBox::enterPressed() { - (*it)->update(height); - height += (*it)->getHeight(); - } -} - -bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) -{ - if(mInterMessageBoxe != NULL) { - throw std::runtime_error("There is a message box already"); - } - - mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); - - return true; -} - -bool MessageBoxManager::isInteractiveMessageBox () -{ - return mInterMessageBoxe != NULL; -} - -void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox) -{ - MessageBoxManagerTimer timer; - timer.current = 0; - timer.max = time; - timer.messageBox = msgbox; - - mTimers.insert(mTimers.end(), timer); -} - -bool MessageBoxManager::removeMessageBox (MessageBox *msgbox) -{ - std::vector::iterator it; - for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) - { - if((*it) == msgbox) - { - delete (*it); - mMessageBoxes.erase(it); - return true; - } - } - return false; -} - -void MessageBoxManager::setMessageBoxSpeed (int speed) -{ - mMessageBoxSpeed = speed; -} - -void MessageBoxManager::enterPressed () -{ - if(mInterMessageBoxe != NULL) - mInterMessageBoxe->enterPressed(); -} - -int MessageBoxManager::readPressedButton () -{ - if(mInterMessageBoxe != NULL) - { - return mInterMessageBoxe->readPressedButton(); - } - return -1; -} - - - - -MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) - : Layout("openmw_messagebox.layout") - , mMessageBoxManager(parMessageBoxManager) - , mMessage(message) -{ - // defines - mFixedWidth = 300; - mBottomPadding = 20; - mNextBoxPadding = 20; - mMarkedToDelete = false; - - getWidget(mMessageWidget, "message"); - - mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->setCaptionWithReplacing(mMessage); - - MyGUI::IntSize size; - size.width = mFixedWidth; - size.height = 100; // dummy - - MyGUI::IntCoord coord; - coord.left = 10; // dummy - coord.top = 10; // dummy - - mMessageWidget->setSize(size); - - MyGUI::IntSize textSize = mMessageWidget->getTextSize(); - - size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box - - mMainWidget->setSize(size); - size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0") - mMessageWidget->setSize(size); -} - -void MessageBox::update (int height) -{ - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntCoord coord; - coord.left = (gameWindowSize.width - mFixedWidth)/2; - coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); - - MyGUI::IntSize size; - size.width = mFixedWidth; - size.height = mHeight; - - mMainWidget->setCoord(coord); - mMainWidget->setSize(size); - mMainWidget->setVisible(true); -} - -int MessageBox::getHeight () -{ - return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox -} - - - -InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : WindowModal("openmw_interactive_messagebox.layout") - , mMessageBoxManager(parMessageBoxManager) - , mButtonPressed(-1) -{ - WindowModal::open(); - - int fixedWidth = 500; - int textPadding = 10; // padding between text-widget and main-widget - int textButtonPadding = 20; // padding between the text-widget und the button-widget - int buttonLeftPadding = 10; // padding between the buttons if horizontal - int buttonTopPadding = 5; // ^-- if vertical - int buttonPadding = 5; // padding between button label and button itself - int buttonMainPadding = 10; // padding between buttons and bottom of the main widget - - mMarkedToDelete = false; - - - getWidget(mMessageWidget, "message"); - getWidget(mButtonsWidget, "buttons"); - - mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->setCaptionWithReplacing(message); - - MyGUI::IntSize textSize = mMessageWidget->getTextSize(); - - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - - int biggestButtonWidth = 0; - int buttonWidth = 0; - int buttonsWidth = 0; - int buttonHeight = 0; - MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - - std::vector::const_iterator it; - for(it = buttons.begin(); it != buttons.end(); ++it) - { - MyGUI::Button* button = mButtonsWidget->createWidget( - MyGUI::WidgetStyle::Child, - std::string("MW_Button"), - dummyCoord, - MyGUI::Align::Default); - button->setCaptionWithReplacing(*it); - - button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); - - mButtons.push_back(button); - - buttonWidth = button->getTextSize().width + 2*buttonPadding + buttonLeftPadding; - buttonsWidth += buttonWidth; - buttonHeight = button->getTextSize().height + 2*buttonPadding + buttonTopPadding; - - if(buttonWidth > biggestButtonWidth) - { - biggestButtonWidth = buttonWidth; - } - } - buttonsWidth += buttonLeftPadding; - - MyGUI::IntSize mainWidgetSize; - if(buttonsWidth < fixedWidth) - { - // on one line - if(textSize.width + 2*textPadding < buttonsWidth) - { - mainWidgetSize.width = buttonsWidth; - } - else - { - mainWidgetSize.width = textSize.width + 3*textPadding; - } - mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; - - MyGUI::IntCoord absCoord; - absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; - absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - - mMainWidget->setCoord(absCoord); - mMainWidget->setSize(mainWidgetSize); - - MyGUI::IntCoord messageWidgetCoord; - messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; - messageWidgetCoord.top = textPadding; - mMessageWidget->setCoord(messageWidgetCoord); - - mMessageWidget->setSize(textSize); - - MyGUI::IntCoord buttonCord; - MyGUI::IntSize buttonSize(0, buttonHeight); - int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonCord.left = left; - buttonCord.top = textSize.height + textButtonPadding; - - buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; - - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); - - left += buttonSize.width + buttonLeftPadding; + if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) + { + buttonActivated(*button); + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); + break; + } } + } - else + + void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) { - // among each other - if(biggestButtonWidth > textSize.width) { - mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; - } - else { - mainWidgetSize.width = textSize.width + 3*textPadding; - } - mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; - - mMainWidget->setSize(mainWidgetSize); - - MyGUI::IntCoord absCoord; - absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; - absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - - mMainWidget->setCoord(absCoord); - mMainWidget->setSize(mainWidgetSize); - - - MyGUI::IntCoord messageWidgetCoord; - messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; - messageWidgetCoord.top = textPadding; - mMessageWidget->setCoord(messageWidgetCoord); - - mMessageWidget->setSize(textSize); - - MyGUI::IntCoord buttonCord; - MyGUI::IntSize buttonSize(0, buttonHeight); - - int top = textButtonPadding + buttonTopPadding + textSize.height; + buttonActivated (pressed); + } + void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) + { + mMarkedToDelete = true; + int index = 0; std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; - - buttonCord.top = top; - buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ - - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); - - top += buttonSize.height + 2*buttonTopPadding; + if(*button == pressed) + { + mButtonPressed = index; + mMessageBoxManager.onButtonPressed(mButtonPressed); + return; + } + index++; } - } -} -void InteractiveMessageBox::enterPressed() -{ - - std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + int InteractiveMessageBox::readPressedButton () { - if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) - { - buttonActivated(*button); - MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); - break; - } + int pressed = mButtonPressed; + mButtonPressed = -1; + return pressed; } } - -void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) -{ - buttonActivated (pressed); -} - -void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) -{ - mMarkedToDelete = true; - int index = 0; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) - { - if(*button == pressed) - { - mButtonPressed = index; - mMessageBoxManager.onButtonPressed(mButtonPressed); - return; - } - index++; - } -} - -int InteractiveMessageBox::readPressedButton () -{ - int pressed = mButtonPressed; - mButtonPressed = -1; - return pressed; -} diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index c031ad6b6..0a7374085 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -10,435 +10,437 @@ #include "tooltips.hpp" -using namespace MWGui; -using namespace Widgets; - namespace { -int wrap(int index, int max) -{ - if (index < 0) - return max - 1; - else if (index >= max) - return 0; - else - return index; -} - -int countParts(const std::string &part, const std::string &race, bool male) -{ - /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs - const MWWorld::Store &store = - MWBase::Environment::get().getWorld()->getStore().get(); - - std::string prefix = - "b_n_" + race + ((male) ? "_m_" : "_f_") + part; - - std::string suffix; - suffix.reserve(prefix.size() + 3); - - int count = -1; - do { - ++count; - suffix = "_" + (boost::format("%02d") % (count + 1)).str(); + int wrap(int index, int max) + { + if (index < 0) + return max - 1; + else if (index >= max) + return 0; + else + return index; } - while (store.search(prefix + suffix) != 0); - if (count == 0 && part == "hair") { - count = -1; + int countParts(const std::string &part, const std::string &race, bool male) + { + /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string prefix = + "b_n_" + race + ((male) ? "_m_" : "_f_") + part; + + std::string suffix; + suffix.reserve(prefix.size() + 3); + + int count = -1; do { ++count; - suffix = (boost::format("%02d") % (count + 1)).str(); + suffix = "_" + (boost::format("%02d") % (count + 1)).str(); } while (store.search(prefix + suffix) != 0); + + if (count == 0 && part == "hair") { + count = -1; + do { + ++count; + suffix = (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + } + return count; } - return count; -} } -RaceDialog::RaceDialog() - : WindowModal("openmw_chargen_race.layout") - , mGenderIndex(0) - , mFaceIndex(0) - , mHairIndex(0) - , mFaceCount(10) - , mHairCount(14) - , mCurrentAngle(0) +namespace MWGui { - // Centre dialog - center(); - setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); - getWidget(mPreviewImage, "PreviewImage"); - - getWidget(mHeadRotate, "HeadRotate"); - mHeadRotate->setScrollRange(50); - mHeadRotate->setScrollPosition(25); - mHeadRotate->setScrollViewPage(10); - mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); - - // Set up next/previous buttons - MyGUI::Button *prevButton, *nextButton; - - setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); - getWidget(prevButton, "PrevGenderButton"); - getWidget(nextButton, "NextGenderButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); - - setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); - getWidget(prevButton, "PrevFaceButton"); - getWidget(nextButton, "NextFaceButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); - - setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); - getWidget(prevButton, "PrevHairButton"); - getWidget(nextButton, "NextHairButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - - setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); - getWidget(mRaceList, "RaceList"); - mRaceList->setScrollVisible(true); - mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - - setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); - getWidget(mSkillList, "SkillList"); - setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); - getWidget(mSpellPowerList, "SpellPowerList"); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); - - updateRaces(); - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -void RaceDialog::open() -{ - WindowModal::open(); - - updateRaces(); - updateSkills(); - updateSpellPowers(); - - mPreview = new MWRender::RaceSelectionPreview(); - mPreview->setup(); - mPreview->update (0); - - const ESM::NPC proto = mPreview->getPrototype(); - setRaceId(proto.mRace); - recountParts(); - - std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); - mFaceIndex = boost::lexical_cast(index) - 1; - - index = proto.mHair.substr(proto.mHair.size() - 2, 2); - mHairIndex = boost::lexical_cast(index) - 1; - - mPreviewImage->setImageTexture ("CharacterHeadPreview"); -} - - -void RaceDialog::setRaceId(const std::string &raceId) -{ - mCurrentRaceId = raceId; - mRaceList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mRaceList->getItemCount(); - for (size_t i = 0; i < count; ++i) + RaceDialog::RaceDialog() + : WindowModal("openmw_chargen_race.layout") + , mGenderIndex(0) + , mFaceIndex(0) + , mHairIndex(0) + , mFaceCount(10) + , mHairCount(14) + , mCurrentAngle(0) { - if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) + // Centre dialog + center(); + + setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); + getWidget(mPreviewImage, "PreviewImage"); + + getWidget(mHeadRotate, "HeadRotate"); + mHeadRotate->setScrollRange(50); + mHeadRotate->setScrollPosition(25); + mHeadRotate->setScrollViewPage(10); + mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); + + // Set up next/previous buttons + MyGUI::Button *prevButton, *nextButton; + + setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); + getWidget(prevButton, "PrevGenderButton"); + getWidget(nextButton, "NextGenderButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); + + setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); + getWidget(prevButton, "PrevFaceButton"); + getWidget(nextButton, "NextFaceButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); + + setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); + getWidget(prevButton, "PrevHairButton"); + getWidget(nextButton, "NextHairButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); + + setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); + getWidget(mRaceList, "RaceList"); + mRaceList->setScrollVisible(true); + mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + + setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); + getWidget(mSkillList, "SkillList"); + setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); + getWidget(mSpellPowerList, "SpellPowerList"); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); + + updateRaces(); + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void RaceDialog::open() + { + WindowModal::open(); + + updateRaces(); + updateSkills(); + updateSpellPowers(); + + mPreview = new MWRender::RaceSelectionPreview(); + mPreview->setup(); + mPreview->update (0); + + const ESM::NPC proto = mPreview->getPrototype(); + setRaceId(proto.mRace); + recountParts(); + + std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); + mFaceIndex = boost::lexical_cast(index) - 1; + + index = proto.mHair.substr(proto.mHair.size() - 2, 2); + mHairIndex = boost::lexical_cast(index) - 1; + + mPreviewImage->setImageTexture ("CharacterHeadPreview"); + } + + + void RaceDialog::setRaceId(const std::string &raceId) + { + mCurrentRaceId = raceId; + mRaceList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mRaceList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mRaceList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; + if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) + { + mRaceList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } + } + + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::close() + { + delete mPreview; + mPreview = 0; + } + + // widget controls + + void RaceDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE) + return; + eventDone(this); + } + + void RaceDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) + { + float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2; + float diff = angle - mCurrentAngle; + mPreview->update (diff); + mCurrentAngle += diff; + } + + void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) + { + mGenderIndex = wrap(mGenderIndex - 1, 2); + + recountParts(); + updatePreview(); + } + + void RaceDialog::onSelectNextGender(MyGUI::Widget*) + { + mGenderIndex = wrap(mGenderIndex + 1, 2); + + recountParts(); + updatePreview(); + } + + void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) + { + do + mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); + while (!isFacePlayable()); + updatePreview(); + } + + void RaceDialog::onSelectNextFace(MyGUI::Widget*) + { + do + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + while (!isFacePlayable()); + updatePreview(); + } + + void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) + { + do + mHairIndex = wrap(mHairIndex - 1, mHairCount); + while (!isHairPlayable()); + updatePreview(); + } + + void RaceDialog::onSelectNextHair(MyGUI::Widget*) + { + do + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isHairPlayable()); + updatePreview(); + } + + bool RaceDialog::isFacePlayable() + { + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(prefix + "head_" + headIndex) == 0) + return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + } + + bool RaceDialog::isHairPlayable() + { + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + if (parts.search(prefix + "hair_" + hairIndex) == 0) + return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + } + + void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) + { + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + const std::string *raceId = mRaceList->getItemDataAt(_index); + if (boost::iequals(mCurrentRaceId, *raceId)) + return; + + mCurrentRaceId = *raceId; + + recountParts(); + + updatePreview(); + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::recountParts() + { + mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); + mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + + mFaceIndex = 0; + mHairIndex = 0; + + while (!isHairPlayable()) + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isFacePlayable()) + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + } + + // update widget content + + void RaceDialog::updatePreview() + { + ESM::NPC record = mPreview->getPrototype(); + record.mRace = mCurrentRaceId; + record.setIsMale(mGenderIndex == 0); + + std::string prefix = + "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + record.mHead = prefix + "head_" + headIndex; + record.mHair = prefix + "hair_" + hairIndex; + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(record.mHair) == 0) { + record.mHair = prefix + "hair" + hairIndex; + } + mPreview->setPrototype(record); + } + + void RaceDialog::updateRaces() + { + mRaceList->removeAllItems(); + + const MWWorld::Store &races = + MWBase::Environment::get().getWorld()->getStore().get(); + + + int index = 0; + MWWorld::Store::iterator it = races.begin(); + for (; it != races.end(); ++it) + { + bool playable = it->mData.mFlags & ESM::Race::Playable; + if (!playable) // Only display playable races + continue; + + mRaceList->addItem(it->mName, it->mId); + if (boost::iequals(it->mId, mCurrentRaceId)) + mRaceList->setIndexSelected(index); + ++index; } } - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::close() -{ - delete mPreview; - mPreview = 0; -} - -// widget controls - -void RaceDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void RaceDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) -{ - float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2; - float diff = angle - mCurrentAngle; - mPreview->update (diff); - mCurrentAngle += diff; -} - -void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) -{ - mGenderIndex = wrap(mGenderIndex - 1, 2); - - recountParts(); - updatePreview(); -} - -void RaceDialog::onSelectNextGender(MyGUI::Widget*) -{ - mGenderIndex = wrap(mGenderIndex + 1, 2); - - recountParts(); - updatePreview(); -} - -void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) -{ - do - mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); - while (!isFacePlayable()); - updatePreview(); -} - -void RaceDialog::onSelectNextFace(MyGUI::Widget*) -{ - do - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); - while (!isFacePlayable()); - updatePreview(); -} - -void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) -{ - do - mHairIndex = wrap(mHairIndex - 1, mHairCount); - while (!isHairPlayable()); - updatePreview(); -} - -void RaceDialog::onSelectNextHair(MyGUI::Widget*) -{ - do - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isHairPlayable()); - updatePreview(); -} - -bool RaceDialog::isFacePlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(prefix + "head_" + headIndex) == 0) - return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -bool RaceDialog::isHairPlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - if (parts.search(prefix + "hair_" + hairIndex) == 0) - return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - const std::string *raceId = mRaceList->getItemDataAt(_index); - if (boost::iequals(mCurrentRaceId, *raceId)) - return; - - mCurrentRaceId = *raceId; - - recountParts(); - - updatePreview(); - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::recountParts() -{ - mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); - mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); - - mFaceIndex = 0; - mHairIndex = 0; - - while (!isHairPlayable()) - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isFacePlayable()) - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); -} - -// update widget content - -void RaceDialog::updatePreview() -{ - ESM::NPC record = mPreview->getPrototype(); - record.mRace = mCurrentRaceId; - record.setIsMale(mGenderIndex == 0); - - std::string prefix = - "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - record.mHead = prefix + "head_" + headIndex; - record.mHair = prefix + "hair_" + hairIndex; - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(record.mHair) == 0) { - record.mHair = prefix + "hair" + hairIndex; - } - mPreview->setPrototype(record); -} - -void RaceDialog::updateRaces() -{ - mRaceList->removeAllItems(); - - const MWWorld::Store &races = - MWBase::Environment::get().getWorld()->getStore().get(); - - - int index = 0; - MWWorld::Store::iterator it = races.begin(); - for (; it != races.end(); ++it) + void RaceDialog::updateSkills() { - bool playable = it->mData.mFlags & ESM::Race::Playable; - if (!playable) // Only display playable races - continue; + for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillItems.clear(); - mRaceList->addItem(it->mName, it->mId); - if (boost::iequals(it->mId, mCurrentRaceId)) - mRaceList->setIndexSelected(index); - ++index; - } -} - -void RaceDialog::updateSkills() -{ - for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillItems.clear(); - - if (mCurrentRaceId.empty()) - return; - - MWSkillPtr skillWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.get().find(mCurrentRaceId); - int count = sizeof(race->mData.mBonus)/sizeof(race->mData.mBonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? - for (int i = 0; i < count; ++i) - { - int skillId = race->mData.mBonus[i].mSkill; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - - skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, - std::string("Skill") + boost::lexical_cast(i)); - skillWidget->setSkillNumber(skillId); - skillWidget->setSkillValue(MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); - ToolTips::createSkillToolTip(skillWidget, skillId); - - - mSkillItems.push_back(skillWidget); - - coord1.top += lineHeight; - } -} - -void RaceDialog::updateSpellPowers() -{ - for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSpellPowerItems.clear(); - - if (mCurrentRaceId.empty()) - return; - - MWSpellPtr spellPowerWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.get().find(mCurrentRaceId); - - std::vector::const_iterator it = race->mPowers.mList.begin(); - std::vector::const_iterator end = race->mPowers.mList.end(); - for (int i = 0; it != end; ++it) - { - const std::string &spellpower = *it; - spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); - spellPowerWidget->setSpellId(spellpower); - spellPowerWidget->setUserString("ToolTipType", "Spell"); - spellPowerWidget->setUserString("Spell", spellpower); - - mSpellPowerItems.push_back(spellPowerWidget); - - coord.top += lineHeight; - ++i; + if (mCurrentRaceId.empty()) + return; + + Widgets::MWSkillPtr skillWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mCurrentRaceId); + int count = sizeof(race->mData.mBonus)/sizeof(race->mData.mBonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? + for (int i = 0; i < count; ++i) + { + int skillId = race->mData.mBonus[i].mSkill; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + + skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, + std::string("Skill") + boost::lexical_cast(i)); + skillWidget->setSkillNumber(skillId); + skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); + ToolTips::createSkillToolTip(skillWidget, skillId); + + + mSkillItems.push_back(skillWidget); + + coord1.top += lineHeight; + } } + + void RaceDialog::updateSpellPowers() + { + for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSpellPowerItems.clear(); + + if (mCurrentRaceId.empty()) + return; + + Widgets::MWSpellPtr spellPowerWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mCurrentRaceId); + + std::vector::const_iterator it = race->mPowers.mList.begin(); + std::vector::const_iterator end = race->mPowers.mList.end(); + for (int i = 0; it != end; ++it) + { + const std::string &spellpower = *it; + spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); + spellPowerWidget->setSpellId(spellpower); + spellPowerWidget->setUserString("ToolTipType", "Spell"); + spellPowerWidget->setUserString("Spell", spellpower); + + mSpellPowerItems.push_back(spellPowerWidget); + + coord.top += lineHeight; + ++i; + } + } + } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 31f5d737b..824929b67 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -11,357 +11,359 @@ #undef min #undef max -using namespace MWGui; -using namespace Widgets; - -const int ReviewDialog::sLineHeight = 18; - -ReviewDialog::ReviewDialog() - : WindowModal("openmw_chargen_review.layout") - , mLastPos(0) +namespace MWGui { - // Centre dialog - center(); - // Setup static stats - MyGUI::Button* button; - getWidget(mNameWidget, "NameText"); - getWidget(button, "NameButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; + const int ReviewDialog::sLineHeight = 18; - getWidget(mRaceWidget, "RaceText"); - getWidget(button, "RaceButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; - - getWidget(mClassWidget, "ClassText"); - getWidget(button, "ClassButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; - - getWidget(mBirthSignWidget, "SignText"); - getWidget(button, "SignButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; - - // Setup dynamic stats - getWidget(mHealth, "Health"); - mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); - mHealth->setValue(45, 45); - - getWidget(mMagicka, "Magicka"); - mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); - mMagicka->setValue(50, 50); - - getWidget(mFatigue, "Fatigue"); - mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); - mFatigue->setValue(160, 160); - - // Setup attributes - - MWAttributePtr attribute; - for (int idx = 0; idx < ESM::Attribute::Length; ++idx) + ReviewDialog::ReviewDialog() + : WindowModal("openmw_chargen_review.layout") + , mLastPos(0) { - getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); - mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); - attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); - attribute->setAttributeValue(MWAttribute::AttributeValue(0, 0)); - } + // Centre dialog + center(); - // Setup skills - getWidget(mSkillView, "SkillView"); - mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + // Setup static stats + MyGUI::Button* button; + getWidget(mNameWidget, "NameText"); + getWidget(button, "NameButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::make_pair(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); - } + getWidget(mRaceWidget, "RaceText"); + getWidget(button, "RaceButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); + getWidget(mClassWidget, "ClassText"); + getWidget(button, "ClassButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); -} + getWidget(mBirthSignWidget, "SignText"); + getWidget(button, "SignButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; -void ReviewDialog::open() -{ - WindowModal::open(); - updateSkillArea(); -} + // Setup dynamic stats + getWidget(mHealth, "Health"); + mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); + mHealth->setValue(45, 45); -void ReviewDialog::setPlayerName(const std::string &name) -{ - mNameWidget->setCaption(name); -} + getWidget(mMagicka, "Magicka"); + mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); + mMagicka->setValue(50, 50); -void ReviewDialog::setRace(const std::string &raceId) -{ - mRaceId = raceId; + getWidget(mFatigue, "Fatigue"); + mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); + mFatigue->setValue(160, 160); - const ESM::Race *race = - MWBase::Environment::get().getWorld()->getStore().get().search(mRaceId); - if (race) - { - ToolTips::createRaceToolTip(mRaceWidget, race); - mRaceWidget->setCaption(race->mName); - } -} + // Setup attributes -void ReviewDialog::setClass(const ESM::Class& class_) -{ - mKlass = class_; - mClassWidget->setCaption(mKlass.mName); - ToolTips::createClassToolTip(mClassWidget, mKlass); -} - -void ReviewDialog::setBirthSign(const std::string& signId) -{ - mBirthSignId = signId; - - const ESM::BirthSign *sign = - MWBase::Environment::get().getWorld()->getStore().get().search(mBirthSignId); - if (sign) - { - mBirthSignWidget->setCaption(sign->mName); - ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); - } -} - -void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) -{ - mHealth->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); -} - -void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) -{ - mMagicka->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); -} - -void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) -{ - mFatigue->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); -} - -void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) -{ - std::map::iterator attr = mAttributeWidgets.find(static_cast(attributeId)); - if (attr == mAttributeWidgets.end()) - return; - - attr->second->setAttributeValue(value); -} - -void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value) -{ - mSkillValues[skillId] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } - -} - -void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); - } - - updateSkillArea(); -} - -void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); - separator->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default); - groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - groupWidget->setCaption(label); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -MyGUI::TextBox* ReviewDialog::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - MyGUI::TextBox* skillValueWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -void ReviewDialog::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); - } - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) - { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); - - for (int i=0; i<2; ++i) + Widgets::MWAttributePtr attribute; + for (int idx = 0; idx < ESM::Attribute::Length; ++idx) { - ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size()-1-i], skillId); + getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); + mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); + attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); + attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0)); } - mSkillWidgetMap[skillId] = widget; - } -} + // Setup skills + getWidget(mSkillView, "SkillView"); + mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); -void ReviewDialog::updateSkillArea() -{ - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (int i = 0; i < ESM::Skill::Length; ++i) + { + mSkillValues.insert(std::make_pair(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); + } + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); + } + + void ReviewDialog::open() { - MyGUI::Gui::getInstance().destroyWidget(*it); + WindowModal::open(); + updateSkillArea(); } - mSkillWidgets.clear(); - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + void ReviewDialog::setPlayerName(const std::string &name) + { + mNameWidget->setCaption(name); + } - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + void ReviewDialog::setRace(const std::string &raceId) + { + mRaceId = raceId; - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().search(mRaceId); + if (race) + { + ToolTips::createRaceToolTip(mRaceWidget, race); + mRaceWidget->setCaption(race->mName); + } + } - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + void ReviewDialog::setClass(const ESM::Class& class_) + { + mKlass = class_; + mClassWidget->setCaption(mKlass.mName); + ToolTips::createClassToolTip(mClassWidget, mKlass); + } - mClientHeight = coord1.top; + void ReviewDialog::setBirthSign(const std::string& signId) + { + mBirthSignId = signId; + + const ESM::BirthSign *sign = + MWBase::Environment::get().getWorld()->getStore().get().search(mBirthSignId); + if (sign) + { + mBirthSignWidget->setCaption(sign->mName); + ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); + } + } + + void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) + { + mHealth->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + + void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) + { + mMagicka->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + + void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) + { + mFatigue->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } + + void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) + { + std::map::iterator attr = mAttributeWidgets.find(static_cast(attributeId)); + if (attr == mAttributeWidgets.end()) + return; + + attr->second->setAttributeValue(value); + } + + void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value) + { + mSkillValues[skillId] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + + widget->setCaption(text); + widget->_setWidgetState(state); + } + + } + + void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) + { + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } + + updateSkillArea(); + } + + void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); + separator->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); + } + + void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + groupWidget->setCaption(label); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + MyGUI::TextBox* ReviewDialog::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* skillNameWidget; + MyGUI::TextBox* skillValueWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; + } + + void ReviewDialog::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size()-1-i], skillId); + } + + mSkillWidgetMap[skillId] = widget; + } + } + + void ReviewDialog::updateSkillArea() + { + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); + } + + // widget controls + + void ReviewDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); + } + + void ReviewDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void ReviewDialog::onNameClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(NAME_DIALOG); + } + + void ReviewDialog::onRaceClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(RACE_DIALOG); + } + + void ReviewDialog::onClassClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(CLASS_DIALOG); + } + + void ReviewDialog::onBirthSignClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(BIRTHSIGN_DIALOG); + } + + void ReviewDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + } - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -// widget controls - -void ReviewDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); -} - -void ReviewDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void ReviewDialog::onNameClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(NAME_DIALOG); -} - -void ReviewDialog::onRaceClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(RACE_DIALOG); -} - -void ReviewDialog::onClassClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(CLASS_DIALOG); -} - -void ReviewDialog::onBirthSignClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(BIRTHSIGN_DIALOG); -} - -void ReviewDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 1935f7a9b..95bf17635 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -10,71 +10,73 @@ #include "formatting.hpp" -using namespace MWGui; - -ScrollWindow::ScrollWindow () - : WindowBase("openmw_scroll.layout") - , mTakeButtonShow(true) - , mTakeButtonAllowed(true) +namespace MWGui { - getWidget(mTextView, "TextView"); - getWidget(mCloseButton, "CloseButton"); - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); + ScrollWindow::ScrollWindow () + : WindowBase("openmw_scroll.layout") + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) + { + getWidget(mTextView, "TextView"); - getWidget(mTakeButton, "TakeButton"); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); + getWidget(mCloseButton, "CloseButton"); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); - center(); -} - -void ScrollWindow::open (MWWorld::Ptr scroll) -{ - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - - mScroll = scroll; - - MWWorld::LiveCellRef *ref = mScroll.get(); - - BookTextParser parser; - MyGUI::IntSize size = parser.parse(ref->mBase->mText, mTextView, 390); - - if (size.height > mTextView->getSize().height) - mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); - else - mTextView->setCanvasSize(410, mTextView->getSize().height); - - mTextView->setViewOffset(MyGUI::IntPoint(0,0)); - - setTakeButtonShow(true); -} - -void ScrollWindow::setTakeButtonShow(bool show) -{ - mTakeButtonShow = show; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void ScrollWindow::setInventoryAllowed(bool allowed) -{ - mTakeButtonAllowed = allowed; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); -} - -void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); - - MWWorld::ActionTake take(mScroll); - take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + getWidget(mTakeButton, "TakeButton"); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); + + center(); + } + + void ScrollWindow::open (MWWorld::Ptr scroll) + { + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); + + mScroll = scroll; + + MWWorld::LiveCellRef *ref = mScroll.get(); + + BookTextParser parser; + MyGUI::IntSize size = parser.parse(ref->mBase->mText, mTextView, 390); + + if (size.height > mTextView->getSize().height) + mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); + else + mTextView->setCanvasSize(410, mTextView->getSize().height); + + mTextView->setViewOffset(MyGUI::IntPoint(0,0)); + + setTakeButtonShow(true); + } + + void ScrollWindow::setTakeButtonShow(bool show) + { + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void ScrollWindow::setInventoryAllowed(bool allowed) + { + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + } + + void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); + + MWWorld::ActionTake take(mScroll); + take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 3439ff31c..1134767f1 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -13,562 +13,565 @@ #include "tooltips.hpp" -using namespace MWGui; -const int StatsWindow::sLineHeight = 18; - -StatsWindow::StatsWindow () - : WindowPinnableBase("openmw_stats_window.layout") - , mSkillView(NULL) - , mClientHeight(0) - , mMajorSkills() - , mMinorSkills() - , mMiscSkills() - , mSkillValues() - , mSkillWidgetMap() - , mFactionWidgetMap() - , mFactions() - , mBirthSignId() - , mReputation(0) - , mBounty(0) - , mSkillWidgets() - , mChanged(true) +namespace MWGui { - setCoord(0,0,498, 342); - const char *names[][2] = + const int StatsWindow::sLineHeight = 18; + + StatsWindow::StatsWindow () + : WindowPinnableBase("openmw_stats_window.layout") + , mSkillView(NULL) + , mClientHeight(0) + , mMajorSkills() + , mMinorSkills() + , mMiscSkills() + , mSkillValues() + , mSkillWidgetMap() + , mFactionWidgetMap() + , mFactions() + , mBirthSignId() + , mReputation(0) + , mBounty(0) + , mSkillWidgets() + , mChanged(true) { - { "Attrib1", "sAttributeStrength" }, - { "Attrib2", "sAttributeIntelligence" }, - { "Attrib3", "sAttributeWillpower" }, - { "Attrib4", "sAttributeAgility" }, - { "Attrib5", "sAttributeSpeed" }, - { "Attrib6", "sAttributeEndurance" }, - { "Attrib7", "sAttributePersonality" }, - { "Attrib8", "sAttributeLuck" }, - { 0, 0 } - }; + setCoord(0,0,498, 342); - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for (int i=0; names[i][0]; ++i) - { - setText (names[i][0], store.get().find (names[i][1])->getString()); - } - - getWidget(mSkillView, "SkillView"); - getWidget(mLeftPane, "LeftPane"); - getWidget(mRightPane, "RightPane"); - - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); - } - - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); -} - -void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); -} - -void StatsWindow::onWindowResize(MyGUI::Window* window) -{ - mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); - mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) -{ - MyGUI::ProgressPtr pt; - getWidget(pt, name); - pt->setProgressRange(max); - pt->setProgressPosition(val); - - std::stringstream out; - out << val << "/" << max; - setText(tname, out.str().c_str()); -} - -void StatsWindow::setPlayerName(const std::string& playerName) -{ - static_cast(mMainWidget)->setCaption(playerName); - adjustWindowCaption(); -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 - }; - - for (int i=0; ids[i]; ++i) - if (ids[i]==id) + const char *names[][2] = { - std::ostringstream valueString; - valueString << value.getModified(); - setText (id, valueString.str()); + { "Attrib1", "sAttributeStrength" }, + { "Attrib2", "sAttributeIntelligence" }, + { "Attrib3", "sAttributeWillpower" }, + { "Attrib4", "sAttributeAgility" }, + { "Attrib5", "sAttributeSpeed" }, + { "Attrib6", "sAttributeEndurance" }, + { "Attrib7", "sAttributePersonality" }, + { "Attrib8", "sAttributeLuck" }, + { 0, 0 } + }; - MyGUI::TextBox* box; - getWidget(box, id); - - if (value.getModified()>value.getBase()) - box->_setWidgetState("increased"); - else if (value.getModified()_setWidgetState("decreased"); - else - box->_setWidgetState("normal"); - - break; + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for (int i=0; names[i][0]; ++i) + { + setText (names[i][0], store.get().find (names[i][1])->getString()); } -} -void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = - { - "HBar", "MBar", "FBar", - 0 - }; + getWidget(mSkillView, "SkillView"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); - for (int i=0; ids[i]; ++i) - { - if (ids[i]==id) + for (int i = 0; i < ESM::Skill::Length; ++i) { - std::string id (ids[i]); - setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); + mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); + } - // health, magicka, fatigue tooltip - MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - if (i==0) + MyGUI::WindowPtr t = static_cast(mMainWidget); + t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); + } + + void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + } + + void StatsWindow::onWindowResize(MyGUI::Window* window) + { + mLeftPane->setCoord( MyGUI::IntCoord(0, 0, 0.44*window->getSize().width, window->getSize().height) ); + mRightPane->setCoord( MyGUI::IntCoord(0.44*window->getSize().width, 0, 0.56*window->getSize().width, window->getSize().height) ); + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); + } + + void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) + { + MyGUI::ProgressPtr pt; + getWidget(pt, name); + pt->setProgressRange(max); + pt->setProgressPosition(val); + + std::stringstream out; + out << val << "/" << max; + setText(tname, out.str().c_str()); + } + + void StatsWindow::setPlayerName(const std::string& playerName) + { + static_cast(mMainWidget)->setCaption(playerName); + adjustWindowCaption(); + } + + void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) + { + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + if (ids[i]==id) { - getWidget(w, "Health"); - w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + std::ostringstream valueString; + valueString << value.getModified(); + setText (id, valueString.str()); + + MyGUI::TextBox* box; + getWidget(box, id); + + if (value.getModified()>value.getBase()) + box->_setWidgetState("increased"); + else if (value.getModified()_setWidgetState("decreased"); + else + box->_setWidgetState("normal"); + + break; } - else if (i==1) + } + + void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) + { + static const char *ids[] = + { + "HBar", "MBar", "FBar", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) { - getWidget(w, "Magicka"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); - } - else if (i==2) - { - getWidget(w, "Fatigue"); - w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + std::string id (ids[i]); + setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); + + // health, magicka, fatigue tooltip + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + if (i==0) + { + getWidget(w, "Health"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + else if (i==1) + { + getWidget(w, "Magicka"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + else if (i==2) + { + getWidget(w, "Fatigue"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } } } } -} -void StatsWindow::setValue (const std::string& id, const std::string& value) -{ - if (id=="name") - setPlayerName (value); - else if (id=="race") - setText ("RaceText", value); - else if (id=="class") - setText ("ClassText", value); -} - -void StatsWindow::setValue (const std::string& id, int value) -{ - if (id=="level") + void StatsWindow::setValue (const std::string& id, const std::string& value) { - std::ostringstream text; - text << value; - setText("LevelText", text.str()); - } -} - -void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) -{ - mSkillValues[parSkill] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } -} - -void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); + if (id=="name") + setPlayerName (value); + else if (id=="race") + setText ("RaceText", value); + else if (id=="class") + setText ("ClassText", value); } - updateSkillArea(); -} - -void StatsWindow::onFrame () -{ - if (!mMainWidget->getVisible()) - return; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - - // level progress - MyGUI::Widget* levelWidget; - for (int i=0; i<2; ++i) + void StatsWindow::setValue (const std::string& id, int value) { - getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); - levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); - levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + if (id=="level") + { + std::ostringstream text; + text << value; + setText("LevelText", text.str()); + } } - setFactions(PCstats.getFactionRanks()); - setExpelled(PCstats.getExpelled ()); + void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) + { + mSkillValues[parSkill] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; - const std::string &signId = - MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + widget->setCaption(text); + widget->_setWidgetState(state); + } + } - setBirthSign(signId); - setReputation (PCstats.getReputation ()); - setBounty (PCstats.getBounty ()); + void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) + { + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } - if (mChanged) updateSkillArea(); -} - -void StatsWindow::setFactions (const FactionList& factions) -{ - if (mFactions != factions) - { - mFactions = factions; - mChanged = true; - } -} - -void StatsWindow::setExpelled (const std::set& expelled) -{ - if (mExpelled != expelled) - { - mExpelled = expelled; - mChanged = true; - } -} - -void StatsWindow::setBirthSign (const std::string& signId) -{ - if (signId != mBirthSignId) - { - mBirthSignId = signId; - mChanged = true; - } -} - -void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", - MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", - MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), - MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - groupWidget->setCaption(label); - groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox *skillNameWidget, *skillValueWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillNameWidget; -} - -void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); } - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + void StatsWindow::onFrame () { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - int progressPercent = (modified - float(static_cast(modified))) * 100; + if (!mMainWidget->getVisible()) + return; - const MWWorld::ESMStore &esmStore = - MWBase::Environment::get().getWorld()->getStore(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - const ESM::Skill* skill = esmStore.get().find(skillId); - assert(skill); + // level progress + MyGUI::Widget* levelWidget; + for (int i=0; i<2; ++i) + { + getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); + levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); + levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + } - std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + setFactions(PCstats.getFactionRanks()); + setExpelled(PCstats.getExpelled ()); - const ESM::Attribute* attr = - esmStore.get().find(skill->mData.mAttribute); - assert(attr); + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), - boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + setBirthSign(signId); + setReputation (PCstats.getReputation ()); + setBounty (PCstats.getBounty ()); + + if (mChanged) + updateSkillArea(); + } + + void StatsWindow::setFactions (const FactionList& factions) + { + if (mFactions != factions) + { + mFactions = factions; + mChanged = true; + } + } + + void StatsWindow::setExpelled (const std::set& expelled) + { + if (mExpelled != expelled) + { + mExpelled = expelled; + mChanged = true; + } + } + + void StatsWindow::setBirthSign (const std::string& signId) + { + if (signId != mBirthSignId) + { + mBirthSignId = signId; + mChanged = true; + } + } + + void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", + MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); + } + + void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* groupWidget = mSkillView->createWidget("SandBrightText", + MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + groupWidget->setCaption(label); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox *skillNameWidget, *skillValueWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; + } + + MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillNameWidget; + } + + void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + int progressPercent = (modified - float(static_cast(modified))) * 100; + + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Skill* skill = esmStore.get().find(skillId); + assert(skill); + + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + const ESM::Attribute* attr = + esmStore.get().find(skill->mData.mAttribute); + assert(attr); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), + boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + } + + mSkillWidgetMap[skillId] = widget; + } + } + + void StatsWindow::updateSkillArea() + { + mChanged = false; + + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); + mClientHeight = 0; + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::NPC *player = + world->getPlayer().getPlayer().get()->mBase; + + // race tooltip + const ESM::Race* playerRace = store.get().find(player->mRace); + + MyGUI::Widget* raceWidget; + getWidget(raceWidget, "RaceText"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + getWidget(raceWidget, "Race_str"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + + // class tooltip + MyGUI::Widget* classWidget; + + const ESM::Class *playerClass = + store.get().find(player->mClass); + + getWidget(classWidget, "ClassText"); + ToolTips::createClassToolTip(classWidget, *playerClass); + getWidget(classWidget, "Class_str"); + ToolTips::createClassToolTip(classWidget, *playerClass); + + if (!mFactions.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + std::set& expelled = PCstats.getExpelled (); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); + FactionList::const_iterator end = mFactions.end(); + for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + { + const ESM::Faction *faction = + store.get().find(it->first); + MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); + + std::string text; + + text += std::string("#DDC79E") + faction->mName; + + if (expelled.find(it->first) != expelled.end()) + text += "\n#{sExpelled}"; + else + { + text += std::string("\n#BF9959") + faction->mRanks[it->second]; + + if (it->second < 9) + { + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + + ESM::RankData rankData = faction->mData.mRankData[it->second+1]; + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.mSkill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + if (rankData.mSkill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); + } + } + + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "TextToolTip"); + w->setUserString("Caption_Text", text); + } + } + + if (!mBirthSignId.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); + const ESM::BirthSign *sign = + store.get().find(mBirthSignId); + MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); + + ToolTips::createBirthsignToolTip(w, mBirthSignId); + } + + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), + boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); } - mSkillWidgetMap[skillId] = widget; - } -} + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), + boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); -void StatsWindow::updateSkillArea() -{ - mChanged = false; - - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillWidgets.clear(); - - mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); - mClientHeight = 0; - - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); - - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); - - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); - - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - - MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::ESMStore &store = world->getStore(); - const ESM::NPC *player = - world->getPlayer().getPlayer().get()->mBase; - - // race tooltip - const ESM::Race* playerRace = store.get().find(player->mRace); - - MyGUI::Widget* raceWidget; - getWidget(raceWidget, "RaceText"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - getWidget(raceWidget, "Race_str"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - - // class tooltip - MyGUI::Widget* classWidget; - - const ESM::Class *playerClass = - store.get().find(player->mClass); - - getWidget(classWidget, "ClassText"); - ToolTips::createClassToolTip(classWidget, *playerClass); - getWidget(classWidget, "Class_str"); - ToolTips::createClassToolTip(classWidget, *playerClass); - - if (!mFactions.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - std::set& expelled = PCstats.getExpelled (); - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); - FactionList::const_iterator end = mFactions.end(); - for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + for (int i=0; i<2; ++i) { - const ESM::Faction *faction = - store.get().find(it->first); - MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); - - std::string text; - - text += std::string("#DDC79E") + faction->mName; - - if (expelled.find(it->first) != expelled.end()) - text += "\n#{sExpelled}"; - else - { - text += std::string("\n#BF9959") + faction->mRanks[it->second]; - - if (it->second < 9) - { - // player doesn't have max rank yet - text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; - - ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - assert(attr1 && attr2); - - text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); - - text += "\n\n#DDC79E#{sFavoriteSkills}"; - text += "\n#BF9959"; - for (int i=0; i<6; ++i) - { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; - if (i<5) - text += ", "; - } - - text += "\n"; - - if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); - if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); - } - } - - w->setUserString("ToolTipType", "Layout"); - w->setUserString("ToolTipLayout", "TextToolTip"); - w->setUserString("Caption_Text", text); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); } + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); } - if (!mBirthSignId.empty()) + void StatsWindow::onPinToggled() { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); - const ESM::BirthSign *sign = - store.get().find(mBirthSignId); - MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); - - ToolTips::createBirthsignToolTip(w, mBirthSignId); + MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); } - - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); - } - - addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); - } - - mClientHeight = coord1.top; - - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::onPinToggled() -{ - MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); } diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index ab2936cfc..d4f8a2533 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -3,68 +3,71 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" -using namespace MWGui; - -TextInputDialog::TextInputDialog() - : WindowModal("openmw_text_input.layout") +namespace MWGui { - // Centre dialog - center(); - getWidget(mTextEdit, "TextEdit"); - mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -void TextInputDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -void TextInputDialog::setTextLabel(const std::string &label) -{ - setText("LabelT", label); -} - -void TextInputDialog::open() -{ - WindowModal::open(); - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -// widget controls - -void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if (mTextEdit->getCaption() == "") + TextInputDialog::TextInputDialog() + : WindowModal("openmw_text_input.layout") { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} + // Centre dialog + center(); -void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) -{ - if (mTextEdit->getCaption() == "") - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + getWidget(mTextEdit, "TextEdit"); + mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); } - else - eventDone(this); + + void TextInputDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void TextInputDialog::setTextLabel(const std::string &label) + { + setText("LabelT", label); + } + + void TextInputDialog::open() + { + WindowModal::open(); + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + } + + // widget controls + + void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) + { + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); + } + + void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) + { + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); + } + } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index b72d27aea..d86aa6941 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -9,761 +9,763 @@ #include "mapwindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; -using namespace MyGUI; - -ToolTips::ToolTips() : - Layout("openmw_tooltips.layout") - , mGameMode(true) - , mFullHelp(false) - , mEnabled(true) - , mFocusToolTipX(0.0) - , mFocusToolTipY(0.0) - , mDelay(0.0) - , mRemainingDelay(0.0) - , mLastMouseX(0) - , mLastMouseY(0) - , mHorizontalScrollIndex(0) -{ - getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); - - mDynamicToolTipBox->setVisible(false); - - // turn off mouse focus so that getMouseFocusWidget returns the correct widget, - // even if the mouse is over the tooltip - mDynamicToolTipBox->setNeedMouseFocus(false); - mMainWidget->setNeedMouseFocus(false); - - mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); - mRemainingDelay = mDelay; - - for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) - { - mMainWidget->getChildAt(i)->setVisible(false); - } -} - -void ToolTips::setEnabled(bool enabled) -{ - mEnabled = enabled; -} - -void ToolTips::onFrame(float frameDuration) +namespace MWGui { - while (mDynamicToolTipBox->getChildCount()) + ToolTips::ToolTips() : + Layout("openmw_tooltips.layout") + , mGameMode(true) + , mFullHelp(false) + , mEnabled(true) + , mFocusToolTipX(0.0) + , mFocusToolTipY(0.0) + , mDelay(0.0) + , mRemainingDelay(0.0) + , mLastMouseX(0) + , mLastMouseY(0) + , mHorizontalScrollIndex(0) { - MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); - } + getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); - // start by hiding everything - for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) - { - mMainWidget->getChildAt(i)->setVisible(false); - } + mDynamicToolTipBox->setVisible(false); - const IntSize &viewSize = RenderManager::getInstance().getViewSize(); + // turn off mouse focus so that getMouseFocusWidget returns the correct widget, + // even if the mouse is over the tooltip + mDynamicToolTipBox->setNeedMouseFocus(false); + mMainWidget->setNeedMouseFocus(false); - if (!mEnabled) - { - return; - } + mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); + mRemainingDelay = mDelay; - if (!mGameMode) - { - const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - - if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) - || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) - || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) { - mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); + mMainWidget->getChildAt(i)->setVisible(false); + } + } - if (mFocusObject.isEmpty ()) - return; + void ToolTips::setEnabled(bool enabled) + { + mEnabled = enabled; + } - const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + void ToolTips::onFrame(float frameDuration) + { - IntSize tooltipSize; - if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) - { - setCoord(0, 0, 300, 300); - mDynamicToolTipBox->setVisible(true); - ToolTipInfo info; - info.caption=mFocusObject.getCellRef().mRefID; - info.icon=""; - tooltipSize = createToolTip(info); - } - else - tooltipSize = getToolTipViaPtr(true); - - IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - - // make the tooltip stay completely in the viewport - if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) - { - tooltipPosition.left = viewSize.width - tooltipSize.width; - } - if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) - { - tooltipPosition.top = viewSize.height - tooltipSize.height; - } - - setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + while (mDynamicToolTipBox->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); } + // start by hiding everything + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) + { + mMainWidget->getChildAt(i)->setVisible(false); + } + + const MyGUI::IntSize &viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + if (!mEnabled) + { + return; + } + + if (!mGameMode) + { + const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); + + if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) + { + mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); + + if (mFocusObject.isEmpty ()) + return; + + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + + MyGUI::IntSize tooltipSize; + if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=mFocusObject.getCellRef().mRefID; + info.icon=""; + tooltipSize = createToolTip(info); + } + else + tooltipSize = getToolTipViaPtr(true); + + MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition() + MyGUI::IntPoint(0, 24); + + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - tooltipSize.width; + } + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - tooltipSize.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + } + + else + { + const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + + if (mousePos == lastPressed) // mouseclick makes tooltip disappear + return; + + if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) + { + mRemainingDelay -= frameDuration; + } + else + { + mHorizontalScrollIndex = 0; + mRemainingDelay = mDelay; + } + mLastMouseX = mousePos.left; + mLastMouseY = mousePos.top; + + + if (mRemainingDelay > 0) + return; + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget(); + if (focus == 0) + return; + + MyGUI::IntSize tooltipSize; + + // try to go 1 level up until there is a widget that has tooltip + // this is necessary because some skin elements are actually separate widgets + int i=0; + while (!focus->isUserString("ToolTipType")) + { + focus = focus->getParent(); + if (!focus) + return; + ++i; + } + + std::string type = focus->getUserString("ToolTipType"); + std::string text = focus->getUserString("ToolTipText"); + + if (type == "") + { + return; + } + + + // special handling for markers on the local map: the tooltip should only be visible + // if the marker is not hidden due to the fog of war. + if (focus->getUserString ("IsMarker") == "true") + { + LocalMapBase::MarkerPosition pos = *focus->getUserData(); + + if (!MWBase::Environment::get().getWorld ()->isPositionExplored (pos.nX, pos.nY, pos.cellX, pos.cellY, pos.interior)) + return; + } + + if (type == "ItemPtr") + { + mFocusObject = *focus->getUserData(); + tooltipSize = getToolTipViaPtr(false); + } + else if (type == "ToolTipInfo") + { + tooltipSize = createToolTip(*focus->getUserData()); + } + else if (type == "AvatarItemSelection") + { + MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); + MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); + int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); + int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); + MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + + mFocusObject = item; + if (!mFocusObject.isEmpty ()) + tooltipSize = getToolTipViaPtr(false); + } + else if (type == "Spell") + { + ToolTipInfo info; + + const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); + info.caption = spell->mName; + Widgets::SpellEffectList effects; + std::vector::const_iterator end = spell->mEffects.mList.end(); + for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + { + Widgets::SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + params.mIsConstant = (spell->mData.mType == ESM::Spell::ST_Ability); + params.mNoTarget = false; + effects.push_back(params); + } + info.effects = effects; + tooltipSize = createToolTip(info); + } + else if (type == "Layout") + { + // tooltip defined in the layout + MyGUI::Widget* tooltip; + getWidget(tooltip, focus->getUserString("ToolTipLayout")); + + tooltip->setVisible(true); + + std::map userStrings = focus->getUserStrings(); + for (std::map::iterator it = userStrings.begin(); + it != userStrings.end(); ++it) + { + if (it->first == "ToolTipType" + || it->first == "ToolTipLayout" + || it->first == "IsMarker") + continue; + + + size_t underscorePos = it->first.find("_"); + std::string propertyKey = it->first.substr(0, underscorePos); + std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); + + MyGUI::Widget* w; + getWidget(w, widgetName); + w->setProperty(propertyKey, it->second); + } + + tooltipSize = tooltip->getSize(); + + tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); + } + else + throw std::runtime_error ("unknown tooltip type"); + + MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition() + MyGUI::IntPoint(0, 24); + + // make the tooltip stay completely in the viewport + if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) + { + tooltipPosition.left = viewSize.width - tooltipSize.width; + } + if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) + { + tooltipPosition.top = viewSize.height - tooltipSize.height; + } + + setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); + } + } else { - const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); - - if (mousePos == lastPressed) // mouseclick makes tooltip disappear - return; - - if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) + if (!mFocusObject.isEmpty()) { - mRemainingDelay -= frameDuration; + MyGUI::IntSize tooltipSize = getToolTipViaPtr(); + + setCoord(viewSize.width/2 - tooltipSize.width/2, + std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), + tooltipSize.width, + tooltipSize.height); + + mDynamicToolTipBox->setVisible(true); } - else - { - mHorizontalScrollIndex = 0; - mRemainingDelay = mDelay; - } - mLastMouseX = mousePos.left; - mLastMouseY = mousePos.top; - - - if (mRemainingDelay > 0) - return; - - Widget* focus = InputManager::getInstance().getMouseFocusWidget(); - if (focus == 0) - return; - - IntSize tooltipSize; - - // try to go 1 level up until there is a widget that has tooltip - // this is necessary because some skin elements are actually separate widgets - int i=0; - while (!focus->isUserString("ToolTipType")) - { - focus = focus->getParent(); - if (!focus) - return; - ++i; - } - - std::string type = focus->getUserString("ToolTipType"); - std::string text = focus->getUserString("ToolTipText"); - - if (type == "") - { - return; - } - - - // special handling for markers on the local map: the tooltip should only be visible - // if the marker is not hidden due to the fog of war. - if (focus->getUserString ("IsMarker") == "true") - { - LocalMapBase::MarkerPosition pos = *focus->getUserData(); - - if (!MWBase::Environment::get().getWorld ()->isPositionExplored (pos.nX, pos.nY, pos.cellX, pos.cellY, pos.interior)) - return; - } - - if (type == "ItemPtr") - { - mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(false); - } - else if (type == "ToolTipInfo") - { - tooltipSize = createToolTip(*focus->getUserData()); - } - else if (type == "AvatarItemSelection") - { - MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); - MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); - int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); - int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); - MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); - - mFocusObject = item; - if (!mFocusObject.isEmpty ()) - tooltipSize = getToolTipViaPtr(false); - } - else if (type == "Spell") - { - ToolTipInfo info; - - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); - info.caption = spell->mName; - Widgets::SpellEffectList effects; - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) - { - Widgets::SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mIsConstant = (spell->mData.mType == ESM::Spell::ST_Ability); - params.mNoTarget = false; - effects.push_back(params); - } - info.effects = effects; - tooltipSize = createToolTip(info); - } - else if (type == "Layout") - { - // tooltip defined in the layout - MyGUI::Widget* tooltip; - getWidget(tooltip, focus->getUserString("ToolTipLayout")); - - tooltip->setVisible(true); - - std::map userStrings = focus->getUserStrings(); - for (std::map::iterator it = userStrings.begin(); - it != userStrings.end(); ++it) - { - if (it->first == "ToolTipType" - || it->first == "ToolTipLayout" - || it->first == "IsMarker") - continue; - - - size_t underscorePos = it->first.find("_"); - std::string propertyKey = it->first.substr(0, underscorePos); - std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); - - MyGUI::Widget* w; - getWidget(w, widgetName); - w->setProperty(propertyKey, it->second); - } - - tooltipSize = tooltip->getSize(); - - tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); - } - else - throw std::runtime_error ("unknown tooltip type"); - - IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - - // make the tooltip stay completely in the viewport - if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) - { - tooltipPosition.left = viewSize.width - tooltipSize.width; - } - if ((tooltipPosition.top + tooltipSize.height) > viewSize.height) - { - tooltipPosition.top = viewSize.height - tooltipSize.height; - } - - setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); } } - else + + void ToolTips::enterGameMode() { - if (!mFocusObject.isEmpty()) + mGameMode = true; + } + + void ToolTips::enterGuiMode() + { + mGameMode = false; + } + + void ToolTips::setFocusObject(const MWWorld::Ptr& focus) + { + mFocusObject = focus; + } + + MyGUI::IntSize ToolTips::getToolTipViaPtr (bool image) + { + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + MyGUI::IntSize tooltipSize; + + const MWWorld::Class& object = MWWorld::Class::get (mFocusObject); + if (!object.hasToolTip(mFocusObject)) + { + mDynamicToolTipBox->setVisible(false); + } + else { - IntSize tooltipSize = getToolTipViaPtr(); - - setCoord(viewSize.width/2 - tooltipSize.width/2, - std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), - tooltipSize.width, - tooltipSize.height); - mDynamicToolTipBox->setVisible(true); + + ToolTipInfo info = object.getToolTipInfo(mFocusObject); + if (!image) + info.icon = ""; + tooltipSize = createToolTip(info); + } + + return tooltipSize; + } + + void ToolTips::findImageExtension(std::string& image) + { + int len = image.size(); + if (len < 4) return; + + if (!Ogre::ResourceGroupManager::getSingleton().resourceExists(Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, image)) + { + // Change texture extension to .dds + image[len-3] = 'd'; + image[len-2] = 'd'; + image[len-1] = 's'; } } -} -void ToolTips::enterGameMode() -{ - mGameMode = true; -} - -void ToolTips::enterGuiMode() -{ - mGameMode = false; -} - -void ToolTips::setFocusObject(const MWWorld::Ptr& focus) -{ - mFocusObject = focus; -} - -IntSize ToolTips::getToolTipViaPtr (bool image) -{ - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); - - IntSize tooltipSize; - - const MWWorld::Class& object = MWWorld::Class::get (mFocusObject); - if (!object.hasToolTip(mFocusObject)) - { - mDynamicToolTipBox->setVisible(false); - } - else + MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { mDynamicToolTipBox->setVisible(true); - ToolTipInfo info = object.getToolTipInfo(mFocusObject); - if (!image) - info.icon = ""; - tooltipSize = createToolTip(info); - } + std::string caption = info.caption; + std::string image = info.icon; + int imageSize = (image != "") ? info.imageSize : 0; + std::string text = info.text; - return tooltipSize; -} + // remove the first newline (easier this way) + if (text.size() > 0 && text[0] == '\n') + text.erase(0, 1); -void ToolTips::findImageExtension(std::string& image) -{ - int len = image.size(); - if (len < 4) return; + if(caption.size() > 0 && isalnum(caption[0])) + caption[0] = toupper(caption[0]); - if (!Ogre::ResourceGroupManager::getSingleton().resourceExists(Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, image)) - { - // Change texture extension to .dds - image[len-3] = 'd'; - image[len-2] = 'd'; - image[len-1] = 's'; - } -} - -IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) -{ - mDynamicToolTipBox->setVisible(true); - - std::string caption = info.caption; - std::string image = info.icon; - int imageSize = (image != "") ? info.imageSize : 0; - std::string text = info.text; - - // remove the first newline (easier this way) - if (text.size() > 0 && text[0] == '\n') - text.erase(0, 1); - - if(caption.size() > 0 && isalnum(caption[0])) - caption[0] = toupper(caption[0]); - - const ESM::Enchantment* enchant = 0; - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - if (info.enchant != "") - { - enchant = store.get().find(info.enchant); - if (enchant->mData.mType == ESM::Enchantment::CastOnce) - text += "\n#{sItemCastOnce}"; - else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) - text += "\n#{sItemCastWhenStrikes}"; - else if (enchant->mData.mType == ESM::Enchantment::WhenUsed) - text += "\n#{sItemCastWhenUsed}"; - else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) - text += "\n#{sItemCastConstant}"; - } - - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); - - const IntPoint padding(8, 8); - - const int maximumWidth = 500; - - const int imageCaptionHPadding = (caption != "" ? 8 : 0); - const int imageCaptionVPadding = (caption != "" ? 4 : 0); - - std::string realImage = "icons\\" + image; - findImageExtension(realImage); - - EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption"); - captionWidget->setProperty("Static", "true"); - captionWidget->setCaptionWithReplacing(caption); - IntSize captionSize = captionWidget->getTextSize(); - - int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); - - EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), Align::Stretch, "ToolTipText"); - textWidget->setProperty("Static", "true"); - textWidget->setProperty("MultiLine", "true"); - textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); - textWidget->setCaptionWithReplacing(text); - textWidget->setTextAlign(Align::HCenter | Align::Top); - IntSize textSize = textWidget->getTextSize(); - - captionSize += IntSize(imageSize, 0); // adjust for image - IntSize totalSize = IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), - ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - - if (!info.effects.empty()) - { - Widget* effectArea = mDynamicToolTipBox->createWidget("", - IntCoord(0, totalSize.height, 300, 300-totalSize.height), - Align::Stretch, "ToolTipEffectArea"); - - IntCoord coord(0, 6, totalSize.width, 24); - - /** - * \todo - * the various potion effects should appear in the tooltip depending if the player - * has enough skill in alchemy to know about the effects of this potion. - */ - - Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget - ("MW_StatName", coord, Align::Default, "ToolTipEffectsWidget"); - effectsWidget->setEffectList(info.effects); - - std::vector effectItems; - effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, info.isPotion ? Widgets::MWEffectList::EF_NoTarget : 0); - totalSize.height += coord.top-6; - totalSize.width = std::max(totalSize.width, coord.width); - } - - if (info.enchant != "") - { - assert(enchant); - Widget* enchantArea = mDynamicToolTipBox->createWidget("", - IntCoord(0, totalSize.height, 300, 300-totalSize.height), - Align::Stretch, "ToolTipEnchantArea"); - - IntCoord coord(0, 6, totalSize.width, 24); - - Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget - ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); - enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); - - std::vector enchantEffectItems; - int flag = (enchant->mData.mType == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; - enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, flag); - totalSize.height += coord.top-6; - totalSize.width = std::max(totalSize.width, coord.width); - - if (enchant->mData.mType == ESM::Enchantment::WhenStrikes - || enchant->mData.mType == ESM::Enchantment::WhenUsed) + const ESM::Enchantment* enchant = 0; + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + if (info.enchant != "") { - int maxCharge = enchant->mData.mCharge; - int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; - - const int chargeWidth = 204; - - TextBox* chargeText = enchantArea->createWidget("SandText", IntCoord(0, 0, 10, 18), Align::Default, "ToolTipEnchantChargeText"); - chargeText->setCaptionWithReplacing("#{sCharges}"); - - const int chargeTextWidth = chargeText->getTextSize().width + 5; - - const int chargeAndTextWidth = chargeWidth + chargeTextWidth; - - totalSize.width = std::max(totalSize.width, chargeAndTextWidth); - - chargeText->setCoord((totalSize.width - chargeAndTextWidth)/2, coord.top+6, chargeTextWidth, 18); - - IntCoord chargeCoord; - if (totalSize.width < chargeWidth) - { - totalSize.width = chargeWidth; - chargeCoord = IntCoord(0, coord.top+6, chargeWidth, 18); - } - else - { - chargeCoord = IntCoord((totalSize.width - chargeAndTextWidth)/2 + chargeTextWidth, coord.top+6, chargeWidth, 18); - } - Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget - ("MW_ChargeBar", chargeCoord, Align::Default, "ToolTipEnchantCharge"); - chargeWidget->setValue(charge, charge); - totalSize.height += 24; + enchant = store.get().find(info.enchant); + if (enchant->mData.mType == ESM::Enchantment::CastOnce) + text += "\n#{sItemCastOnce}"; + else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) + text += "\n#{sItemCastWhenStrikes}"; + else if (enchant->mData.mType == ESM::Enchantment::WhenUsed) + text += "\n#{sItemCastWhenUsed}"; + else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) + text += "\n#{sItemCastConstant}"; } - } - captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, - (captionHeight-captionSize.height)/2, - captionSize.width-imageSize, - captionSize.height); + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); - //if its too long we do hscroll with the caption - if (captionSize.width > maximumWidth) - { - mHorizontalScrollIndex = mHorizontalScrollIndex + 2; - if (mHorizontalScrollIndex > captionSize.width){ - mHorizontalScrollIndex = -totalSize.width; - } - int horizontal_scroll = mHorizontalScrollIndex; - if (horizontal_scroll < 40){ - horizontal_scroll = 40; - }else{ - horizontal_scroll = 80 - mHorizontalScrollIndex; - } - captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); - } else { - captionWidget->setPosition (captionWidget->getPosition() + padding); - } + const MyGUI::IntPoint padding(8, 8); - textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + const int maximumWidth = 500; - if (image != "") - { - ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", - IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), - Align::Left | Align::Top, "ToolTipImage"); - imageWidget->setImageTexture(realImage); - imageWidget->setPosition (imageWidget->getPosition() + padding); - } + const int imageCaptionHPadding = (caption != "" ? 8 : 0); + const int imageCaptionVPadding = (caption != "" ? 4 : 0); - totalSize += IntSize(padding.left*2, padding.top*2); + std::string realImage = "icons\\" + image; + findImageExtension(realImage); - return totalSize; -} + MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); + captionWidget->setProperty("Static", "true"); + captionWidget->setCaptionWithReplacing(caption); + MyGUI::IntSize captionSize = captionWidget->getTextSize(); -std::string ToolTips::toString(const float value) -{ - std::ostringstream stream; - stream << std::setprecision(3) << value; - return stream.str(); -} + int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); -std::string ToolTips::toString(const int value) -{ - std::ostringstream stream; - stream << value; - return stream.str(); -} + MyGUI::EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), MyGUI::Align::Stretch, "ToolTipText"); + textWidget->setProperty("Static", "true"); + textWidget->setProperty("MultiLine", "true"); + textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); + textWidget->setCaptionWithReplacing(text); + textWidget->setTextAlign(MyGUI::Align::HCenter | MyGUI::Align::Top); + MyGUI::IntSize textSize = textWidget->getTextSize(); -std::string ToolTips::getValueString(const int value, const std::string& prefix) -{ - if (value == 0) - return ""; - else - return "\n" + prefix + ": " + toString(value); -} + captionSize += MyGUI::IntSize(imageSize, 0); // adjust for image + MyGUI::IntSize totalSize = MyGUI::IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), + ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); -std::string ToolTips::getMiscString(const std::string& text, const std::string& prefix) -{ - if (text == "") - return ""; - else - return "\n" + prefix + ": " + text; -} - -std::string ToolTips::getCountString(const int value) -{ - if (value == 1) - return ""; - else - return " (" + boost::lexical_cast(value) + ")"; -} - -void ToolTips::toggleFullHelp() -{ - mFullHelp = !mFullHelp; -} - -bool ToolTips::getFullHelp() const -{ - return mFullHelp; -} - -void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) -{ - mFocusToolTipX = (min_x + max_x) / 2; - mFocusToolTipY = min_y; -} - -void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId) -{ - if (skillId == -1) - return; - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const ESM::Skill* skill = store.get().find(skillId); - assert(skill); - - const ESM::Attribute* attr = - store.get().find(skill->mData.mAttribute); - assert(attr); - std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip"); - widget->setUserString("Caption_SkillNoProgressName", "#{"+skillNameId+"}"); - widget->setUserString("Caption_SkillNoProgressDescription", skill->mDescription); - widget->setUserString("Caption_SkillNoProgressAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - widget->setUserString("ImageTexture_SkillNoProgressImage", icon); -} - -void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId) -{ - if (attributeId == -1) - return; - - std::string icon = ESM::Attribute::sAttributeIcons[attributeId]; - std::string name = ESM::Attribute::sGmstAttributeIds[attributeId]; - std::string desc = ESM::Attribute::sGmstAttributeDescIds[attributeId]; - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "AttributeToolTip"); - widget->setUserString("Caption_AttributeName", "#{"+name+"}"); - widget->setUserString("Caption_AttributeDescription", "#{"+desc+"}"); - widget->setUserString("ImageTexture_AttributeImage", icon); -} - -void ToolTips::createSpecializationToolTip(MyGUI::Widget* widget, const std::string& name, int specId) -{ - widget->setUserString("Caption_CenteredCaption", name); - std::string specText; - // get all skills of this specialisation - const MWWorld::Store &skills = - MWBase::Environment::get().getWorld()->getStore().get(); - - MWWorld::Store::iterator it = skills.begin(); - for (; it != skills.end(); ++it) - { - if (it->mData.mSpecialization == specId) - specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->mIndex] + "}"; - } - widget->setUserString("Caption_CenteredCaptionText", specText); - widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); - widget->setUserString("ToolTipType", "Layout"); -} - -void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId) -{ - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::BirthSign *sign = store.get().find(birthsignId); - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "BirthSignToolTip"); - std::string image = sign->mTexture; - image.replace(image.size()-3, 3, "dds"); - widget->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); - std::string text; - - text += sign->mName; - text += "\n#BF9959" + sign->mDescription; - - std::vector abilities, powers, spells; - - std::vector::const_iterator it = sign->mPowers.mList.begin(); - std::vector::const_iterator end = sign->mPowers.mList.end(); - for (; it != end; ++it) - { - const std::string &spellId = *it; - const ESM::Spell *spell = store.get().search(spellId); - if (!spell) - continue; // Skip spells which cannot be found - ESM::Spell::SpellType type = static_cast(spell->mData.mType); - if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) - continue; // We only want spell, ability and powers. - - if (type == ESM::Spell::ST_Ability) - abilities.push_back(spellId); - else if (type == ESM::Spell::ST_Power) - powers.push_back(spellId); - else if (type == ESM::Spell::ST_Spell) - spells.push_back(spellId); - } - - struct { - const std::vector &spells; - std::string label; - } - categories[3] = { - {abilities, "sBirthsignmenu1"}, - {powers, "sPowers"}, - {spells, "sBirthsignmenu2"} - }; - - for (int category = 0; category < 3; ++category) - { - for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + if (!info.effects.empty()) { - if (it == categories[category].spells.begin()) - { - text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; - } + MyGUI::Widget* effectArea = mDynamicToolTipBox->createWidget("", + MyGUI::IntCoord(0, totalSize.height, 300, 300-totalSize.height), + MyGUI::Align::Stretch, "ToolTipEffectArea"); + MyGUI::IntCoord coord(0, 6, totalSize.width, 24); + + /** + * \todo + * the various potion effects should appear in the tooltip depending if the player + * has enough skill in alchemy to know about the effects of this potion. + */ + + Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget + ("MW_StatName", coord, MyGUI::Align::Default, "ToolTipEffectsWidget"); + effectsWidget->setEffectList(info.effects); + + std::vector effectItems; + effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, info.isPotion ? Widgets::MWEffectList::EF_NoTarget : 0); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + } + + if (info.enchant != "") + { + assert(enchant); + MyGUI::Widget* enchantArea = mDynamicToolTipBox->createWidget("", + MyGUI::IntCoord(0, totalSize.height, 300, 300-totalSize.height), + MyGUI::Align::Stretch, "ToolTipEnchantArea"); + + MyGUI::IntCoord coord(0, 6, totalSize.width, 24); + + Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget + ("MW_StatName", coord, MyGUI::Align::Default, "ToolTipEnchantWidget"); + enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); + + std::vector enchantEffectItems; + int flag = (enchant->mData.mType == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; + enchantWidget->createEffectWidgets(enchantEffectItems, enchantArea, coord, true, flag); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + + if (enchant->mData.mType == ESM::Enchantment::WhenStrikes + || enchant->mData.mType == ESM::Enchantment::WhenUsed) + { + int maxCharge = enchant->mData.mCharge; + int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; + + const int chargeWidth = 204; + + MyGUI::TextBox* chargeText = enchantArea->createWidget("SandText", MyGUI::IntCoord(0, 0, 10, 18), MyGUI::Align::Default, "ToolTipEnchantChargeText"); + chargeText->setCaptionWithReplacing("#{sCharges}"); + + const int chargeTextWidth = chargeText->getTextSize().width + 5; + + const int chargeAndTextWidth = chargeWidth + chargeTextWidth; + + totalSize.width = std::max(totalSize.width, chargeAndTextWidth); + + chargeText->setCoord((totalSize.width - chargeAndTextWidth)/2, coord.top+6, chargeTextWidth, 18); + + MyGUI::IntCoord chargeCoord; + if (totalSize.width < chargeWidth) + { + totalSize.width = chargeWidth; + chargeCoord = MyGUI::IntCoord(0, coord.top+6, chargeWidth, 18); + } + else + { + chargeCoord = MyGUI::IntCoord((totalSize.width - chargeAndTextWidth)/2 + chargeTextWidth, coord.top+6, chargeWidth, 18); + } + Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget + ("MW_ChargeBar", chargeCoord, MyGUI::Align::Default, "ToolTipEnchantCharge"); + chargeWidget->setValue(charge, charge); + totalSize.height += 24; + } + } + + captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, + (captionHeight-captionSize.height)/2, + captionSize.width-imageSize, + captionSize.height); + + //if its too long we do hscroll with the caption + if (captionSize.width > maximumWidth) + { + mHorizontalScrollIndex = mHorizontalScrollIndex + 2; + if (mHorizontalScrollIndex > captionSize.width){ + mHorizontalScrollIndex = -totalSize.width; + } + int horizontal_scroll = mHorizontalScrollIndex; + if (horizontal_scroll < 40){ + horizontal_scroll = 40; + }else{ + horizontal_scroll = 80 - mHorizontalScrollIndex; + } + captionWidget->setPosition (MyGUI::IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); + } else { + captionWidget->setPosition (captionWidget->getPosition() + padding); + } + + textWidget->setPosition (textWidget->getPosition() + MyGUI::IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + + if (image != "") + { + MyGUI::ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", + MyGUI::IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), + MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipImage"); + imageWidget->setImageTexture(realImage); + imageWidget->setPosition (imageWidget->getPosition() + padding); + } + + totalSize += MyGUI::IntSize(padding.left*2, padding.top*2); + + return totalSize; + } + + std::string ToolTips::toString(const float value) + { + std::ostringstream stream; + stream << std::setprecision(3) << value; + return stream.str(); + } + + std::string ToolTips::toString(const int value) + { + std::ostringstream stream; + stream << value; + return stream.str(); + } + + std::string ToolTips::getValueString(const int value, const std::string& prefix) + { + if (value == 0) + return ""; + else + return "\n" + prefix + ": " + toString(value); + } + + std::string ToolTips::getMiscString(const std::string& text, const std::string& prefix) + { + if (text == "") + return ""; + else + return "\n" + prefix + ": " + text; + } + + std::string ToolTips::getCountString(const int value) + { + if (value == 1) + return ""; + else + return " (" + boost::lexical_cast(value) + ")"; + } + + void ToolTips::toggleFullHelp() + { + mFullHelp = !mFullHelp; + } + + bool ToolTips::getFullHelp() const + { + return mFullHelp; + } + + void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) + { + mFocusToolTipX = (min_x + max_x) / 2; + mFocusToolTipY = min_y; + } + + void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId) + { + if (skillId == -1) + return; + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const ESM::Skill* skill = store.get().find(skillId); + assert(skill); + + const ESM::Attribute* attr = + store.get().find(skill->mData.mAttribute); + assert(attr); + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "SkillNoProgressToolTip"); + widget->setUserString("Caption_SkillNoProgressName", "#{"+skillNameId+"}"); + widget->setUserString("Caption_SkillNoProgressDescription", skill->mDescription); + widget->setUserString("Caption_SkillNoProgressAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + widget->setUserString("ImageTexture_SkillNoProgressImage", icon); + } + + void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId) + { + if (attributeId == -1) + return; + + std::string icon = ESM::Attribute::sAttributeIcons[attributeId]; + std::string name = ESM::Attribute::sGmstAttributeIds[attributeId]; + std::string desc = ESM::Attribute::sGmstAttributeDescIds[attributeId]; + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", "#{"+name+"}"); + widget->setUserString("Caption_AttributeDescription", "#{"+desc+"}"); + widget->setUserString("ImageTexture_AttributeImage", icon); + } + + void ToolTips::createSpecializationToolTip(MyGUI::Widget* widget, const std::string& name, int specId) + { + widget->setUserString("Caption_CenteredCaption", name); + std::string specText; + // get all skills of this specialisation + const MWWorld::Store &skills = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Store::iterator it = skills.begin(); + for (; it != skills.end(); ++it) + { + if (it->mData.mSpecialization == specId) + specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->mIndex] + "}"; + } + widget->setUserString("Caption_CenteredCaptionText", specText); + widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); + widget->setUserString("ToolTipType", "Layout"); + } + + void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::BirthSign *sign = store.get().find(birthsignId); + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "BirthSignToolTip"); + std::string image = sign->mTexture; + image.replace(image.size()-3, 3, "dds"); + widget->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); + std::string text; + + text += sign->mName; + text += "\n#BF9959" + sign->mDescription; + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = sign->mPowers.mList.begin(); + std::vector::const_iterator end = sign->mPowers.mList.end(); + for (; it != end; ++it) + { const std::string &spellId = *it; + const ESM::Spell *spell = store.get().search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->mData.mType); + if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) + continue; // We only want spell, ability and powers. - const ESM::Spell *spell = store.get().find(spellId); - text += "\n#BF9959" + spell->mName; + if (type == ESM::Spell::ST_Ability) + abilities.push_back(spellId); + else if (type == ESM::Spell::ST_Power) + powers.push_back(spellId); + else if (type == ESM::Spell::ST_Spell) + spells.push_back(spellId); } + + struct { + const std::vector &spells; + std::string label; + } + categories[3] = { + {abilities, "sBirthsignmenu1"}, + {powers, "sPowers"}, + {spells, "sBirthsignmenu2"} + }; + + for (int category = 0; category < 3; ++category) + { + for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + { + if (it == categories[category].spells.begin()) + { + text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; + } + + const std::string &spellId = *it; + + const ESM::Spell *spell = store.get().find(spellId); + text += "\n#BF9959" + spell->mName; + } + } + + widget->setUserString("Caption_BirthSignText", text); + } + + void ToolTips::createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace) + { + widget->setUserString("Caption_CenteredCaption", playerRace->mName); + widget->setUserString("Caption_CenteredCaptionText", playerRace->mDescription); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); + } + + void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass) + { + if (playerClass.mName == "") + return; + + int spec = playerClass.mData.mSpecialization; + std::string specStr; + if (spec == 0) + specStr = "#{sSpecializationCombat}"; + else if (spec == 1) + specStr = "#{sSpecializationMagic}"; + else if (spec == 2) + specStr = "#{sSpecializationStealth}"; + + widget->setUserString("Caption_ClassName", playerClass.mName); + widget->setUserString("Caption_ClassDescription", playerClass.mDescription); + widget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "ClassToolTip"); + } + + void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id) + { + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(id); + const std::string &name = ESM::MagicEffect::effectIdToString (id); + + std::string icon = effect->mIcon; + + int slashPos = icon.find("\\"); + icon.insert(slashPos+1, "b_"); + + icon[icon.size()-3] = 'd'; + icon[icon.size()-2] = 'd'; + icon[icon.size()-1] = 's'; + + icon = "icons\\" + icon; + + std::vector schools; + schools.push_back ("#{sSchoolAlteration}"); + schools.push_back ("#{sSchoolConjuration}"); + schools.push_back ("#{sSchoolDestruction}"); + schools.push_back ("#{sSchoolIllusion}"); + schools.push_back ("#{sSchoolMysticism}"); + schools.push_back ("#{sSchoolRestoration}"); + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); + widget->setUserString("Caption_MagicEffectName", "#{" + name + "}"); + widget->setUserString("Caption_MagicEffectDescription", effect->mDescription); + widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]); + widget->setUserString("ImageTexture_MagicEffectImage", icon); + } + + void ToolTips::setDelay(float delay) + { + mDelay = delay; + mRemainingDelay = mDelay; } - widget->setUserString("Caption_BirthSignText", text); -} - -void ToolTips::createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace) -{ - widget->setUserString("Caption_CenteredCaption", playerRace->mName); - widget->setUserString("Caption_CenteredCaptionText", playerRace->mDescription); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); -} - -void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass) -{ - if (playerClass.mName == "") - return; - - int spec = playerClass.mData.mSpecialization; - std::string specStr; - if (spec == 0) - specStr = "#{sSpecializationCombat}"; - else if (spec == 1) - specStr = "#{sSpecializationMagic}"; - else if (spec == 2) - specStr = "#{sSpecializationStealth}"; - - widget->setUserString("Caption_ClassName", playerClass.mName); - widget->setUserString("Caption_ClassDescription", playerClass.mDescription); - widget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "ClassToolTip"); -} - -void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id) -{ - const ESM::MagicEffect* effect = - MWBase::Environment::get().getWorld ()->getStore ().get().find(id); - const std::string &name = ESM::MagicEffect::effectIdToString (id); - - std::string icon = effect->mIcon; - - int slashPos = icon.find("\\"); - icon.insert(slashPos+1, "b_"); - - icon[icon.size()-3] = 'd'; - icon[icon.size()-2] = 'd'; - icon[icon.size()-1] = 's'; - - icon = "icons\\" + icon; - - std::vector schools; - schools.push_back ("#{sSchoolAlteration}"); - schools.push_back ("#{sSchoolConjuration}"); - schools.push_back ("#{sSchoolDestruction}"); - schools.push_back ("#{sSchoolIllusion}"); - schools.push_back ("#{sSchoolMysticism}"); - schools.push_back ("#{sSchoolRestoration}"); - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); - widget->setUserString("Caption_MagicEffectName", "#{" + name + "}"); - widget->setUserString("Caption_MagicEffectDescription", effect->mDescription); - widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]); - widget->setUserString("ImageTexture_MagicEffectImage", icon); -} - -void ToolTips::setDelay(float delay) -{ - mDelay = delay; - mRemainingDelay = mDelay; } diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index e6c8b1d77..1662c0597 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -12,882 +12,886 @@ #undef min #undef max -using namespace MWGui; -using namespace MWGui::Widgets; - -/* Helper functions */ - -/* - * Fixes the filename of a texture path to use the correct .dds extension. - * This is needed on some ESM entries which point to a .tga file instead. - */ -void MWGui::Widgets::fixTexturePath(std::string &path) +namespace MWGui { - int offset = path.rfind("."); - if (offset < 0) - return; - path.replace(offset, path.length() - offset, ".dds"); -} - -/* MWSkill */ - -MWSkill::MWSkill() - : mSkillId(ESM::Skill::Length) - , mSkillNameWidget(NULL) - , mSkillValueWidget(NULL) -{ -} - -void MWSkill::setSkillId(ESM::Skill::SkillEnum skill) -{ - mSkillId = skill; - updateWidgets(); -} - -void MWSkill::setSkillNumber(int skill) -{ - if (skill < 0) - setSkillId(ESM::Skill::Length); - else if (skill < ESM::Skill::Length) - setSkillId(static_cast(skill)); - else - throw new std::runtime_error("Skill number out of range"); -} - -void MWSkill::setSkillValue(const SkillValue& value) -{ - mValue = value; - updateWidgets(); -} - -void MWSkill::updateWidgets() -{ - if (mSkillNameWidget) + namespace Widgets { - if (mSkillId == ESM::Skill::Length) + + /* Helper functions */ + + /* + * Fixes the filename of a texture path to use the correct .dds extension. + * This is needed on some ESM entries which point to a .tga file instead. + */ + void fixTexturePath(std::string &path) { - static_cast(mSkillNameWidget)->setCaption(""); - } - else - { - const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); - static_cast(mSkillNameWidget)->setCaption(name); - } - } - if (mSkillValueWidget) - { - SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); - static_cast(mSkillValueWidget)->setCaption(boost::lexical_cast(modified)); - if (modified > base) - mSkillValueWidget->_setWidgetState("increased"); - else if (modified < base) - mSkillValueWidget->_setWidgetState("decreased"); - else - mSkillValueWidget->_setWidgetState("normal"); - } -} - -void MWSkill::onClicked(MyGUI::Widget* _sender) -{ - eventClicked(this); -} - -MWSkill::~MWSkill() -{ -} - -void MWSkill::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mSkillNameWidget, "StatName"); - assignWidget(mSkillValueWidget, "StatValue"); - - MyGUI::Button* button; - assignWidget(button, "StatNameButton"); - if (button) - { - mSkillNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); - } - - button = 0; - assignWidget(button, "StatValueButton"); - if (button) - { - mSkillNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); - } -} - -/* MWAttribute */ - -MWAttribute::MWAttribute() - : mId(-1) - , mAttributeNameWidget(NULL) - , mAttributeValueWidget(NULL) -{ -} - -void MWAttribute::setAttributeId(int attributeId) -{ - mId = attributeId; - updateWidgets(); -} - -void MWAttribute::setAttributeValue(const AttributeValue& value) -{ - mValue = value; - updateWidgets(); -} - -void MWAttribute::onClicked(MyGUI::Widget* _sender) -{ - eventClicked(this); -} - -void MWAttribute::updateWidgets() -{ - if (mAttributeNameWidget) - { - if (mId < 0 || mId >= 8) - { - static_cast(mAttributeNameWidget)->setCaption(""); - } - else - { - static const char *attributes[8] = { - "sAttributeStrength", - "sAttributeIntelligence", - "sAttributeWillpower", - "sAttributeAgility", - "sAttributeSpeed", - "sAttributeEndurance", - "sAttributePersonality", - "sAttributeLuck" - }; - const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); - static_cast(mAttributeNameWidget)->setCaption(name); - } - } - if (mAttributeValueWidget) - { - AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); - static_cast(mAttributeValueWidget)->setCaption(boost::lexical_cast(modified)); - if (modified > base) - mAttributeValueWidget->_setWidgetState("increased"); - else if (modified < base) - mAttributeValueWidget->_setWidgetState("decreased"); - else - mAttributeValueWidget->_setWidgetState("normal"); - } -} - -MWAttribute::~MWAttribute() -{ -} - -void MWAttribute::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mAttributeNameWidget, "StatName"); - assignWidget(mAttributeValueWidget, "StatValue"); - - MyGUI::Button* button; - assignWidget(button, "StatNameButton"); - if (button) - { - mAttributeNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); - } - - button = 0; - assignWidget(button, "StatValueButton"); - if (button) - { - mAttributeValueWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); - } -} - -/* MWSpell */ - -MWSpell::MWSpell() - : mSpellNameWidget(NULL) -{ -} - -void MWSpell::setSpellId(const std::string &spellId) -{ - mId = spellId; - updateWidgets(); -} - -void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags) -{ - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Spell *spell = store.get().search(mId); - MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); - - MWSpellEffectPtr effect = NULL; - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) - { - effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mIsConstant = (flags & MWEffectList::EF_Constant); - params.mNoTarget = (flags & MWEffectList::EF_NoTarget); - effect->setSpellEffect(params); - effects.push_back(effect); - coord.top += effect->getHeight(); - coord.width = std::max(coord.width, effect->getRequestedWidth()); - } -} - -void MWSpell::updateWidgets() -{ - if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) - { - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Spell *spell = store.get().search(mId); - if (spell) - static_cast(mSpellNameWidget)->setCaption(spell->mName); - else - static_cast(mSpellNameWidget)->setCaption(""); - } -} - -void MWSpell::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mSpellNameWidget, "StatName"); -} - -MWSpell::~MWSpell() -{ -} - -/* MWEffectList */ - -MWEffectList::MWEffectList() - : mEffectList(0) -{ -} - -void MWEffectList::setEffectList(const SpellEffectList& list) -{ - mEffectList = list; - updateWidgets(); -} - -void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, bool center, int flags) -{ - // We don't know the width of all the elements beforehand, so we do it in - // 2 steps: first, create all widgets and check their width.... - MWSpellEffectPtr effect = NULL; - int maxwidth = coord.width; - - for (SpellEffectList::iterator it=mEffectList.begin(); - it != mEffectList.end(); ++it) - { - effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; - it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; - effect->setSpellEffect(*it); - effects.push_back(effect); - if (effect->getRequestedWidth() > maxwidth) - maxwidth = effect->getRequestedWidth(); - - coord.top += effect->getHeight(); - } - - // ... then adjust the size for all widgets - for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) - { - effect = static_cast(*it); - bool needcenter = center && (maxwidth > effect->getRequestedWidth()); - int diff = maxwidth - effect->getRequestedWidth(); - if (needcenter) - { - effect->setCoord(diff/2, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); - } - else - { - effect->setCoord(0, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); - } - } - - // inform the parent about width - coord.width = maxwidth; -} - -void MWEffectList::updateWidgets() -{ -} - -void MWEffectList::initialiseOverride() -{ - Base::initialiseOverride(); -} - -MWEffectList::~MWEffectList() -{ -} - -SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) -{ - SpellEffectList result; - std::vector::const_iterator end = effects->mList.end(); - for (std::vector::const_iterator it = effects->mList.begin(); it != end; ++it) - { - SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; - result.push_back(params); - } - return result; -} - -/* MWSpellEffect */ - -MWSpellEffect::MWSpellEffect() - : mImageWidget(NULL) - , mTextWidget(NULL) - , mRequestedWidth(0) -{ -} - -void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) -{ - mEffectParams = params; - updateWidgets(); -} - -void MWSpellEffect::updateWidgets() -{ - if (!mEffectParams.mKnown) - { - mTextWidget->setCaption ("?"); - mRequestedWidth = mTextWidget->getTextSize().width + 24; - mImageWidget->setImageTexture (""); - return; - } - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::MagicEffect *magicEffect = - store.get().search(mEffectParams.mEffectID); - - assert(magicEffect); - - std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); - std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); - std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; - std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); - std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); - - std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); - std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); - - if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); - } - if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); - } - - if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) - { - if (mEffectParams.mMagnMin == mEffectParams.mMagnMax) - spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts); - else - { - spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + to + boost::lexical_cast(mEffectParams.mMagnMax) + " " + pts; - } - } - - // constant effects have no duration and no target - if (!mEffectParams.mIsConstant) - { - if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + int offset = path.rfind("."); + if (offset < 0) + return; + path.replace(offset, path.length() - offset, ".dds"); } - if (mEffectParams.mArea > 0) + /* MWSkill */ + + MWSkill::MWSkill() + : mSkillId(ESM::Skill::Length) + , mSkillNameWidget(NULL) + , mSkillValueWidget(NULL) { - spellLine += " #{sin} " + boost::lexical_cast(mEffectParams.mArea) + " #{sfootarea}"; } - // potions have no target - if (!mEffectParams.mNoTarget) + void MWSkill::setSkillId(ESM::Skill::SkillEnum skill) { - std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); - if (mEffectParams.mRange == ESM::RT_Self) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); - else if (mEffectParams.mRange == ESM::RT_Touch) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); - else if (mEffectParams.mRange == ESM::RT_Target) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); + mSkillId = skill; + updateWidgets(); } - } - static_cast(mTextWidget)->setCaptionWithReplacing(spellLine); - mRequestedWidth = mTextWidget->getTextSize().width + 24; - - std::string path = std::string("icons\\") + magicEffect->mIcon; - fixTexturePath(path); - mImageWidget->setImageTexture(path); -} - -MWSpellEffect::~MWSpellEffect() -{ -} - -void MWSpellEffect::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mTextWidget, "Text"); - assignWidget(mImageWidget, "Image"); -} - -/* MWDynamicStat */ - -MWDynamicStat::MWDynamicStat() -: mValue(0) -, mMax(1) -, mTextWidget(NULL) -, mBarWidget(NULL) -, mBarTextWidget(NULL) -{ -} - -void MWDynamicStat::setValue(int cur, int max) -{ - mValue = cur; - mMax = max; - - if (mBarWidget) - { - mBarWidget->setProgressRange(mMax); - mBarWidget->setProgressPosition(mValue); - } - - - if (mBarTextWidget) - { - if (mValue >= 0 && mMax > 0) + void MWSkill::setSkillNumber(int skill) { - std::stringstream out; - out << mValue << "/" << mMax; - static_cast(mBarTextWidget)->setCaption(out.str().c_str()); + if (skill < 0) + setSkillId(ESM::Skill::Length); + else if (skill < ESM::Skill::Length) + setSkillId(static_cast(skill)); + else + throw new std::runtime_error("Skill number out of range"); } - else - static_cast(mBarTextWidget)->setCaption(""); - } -} -void MWDynamicStat::setTitle(const std::string& text) -{ - if (mTextWidget) - static_cast(mTextWidget)->setCaption(text); -} -MWDynamicStat::~MWDynamicStat() -{ -} - -void MWDynamicStat::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mTextWidget, "Text"); - assignWidget(mBarWidget, "Bar"); - assignWidget(mBarTextWidget, "BarText"); -} - - - - -// --------------------------------------------------------------------------------------------------------------------- - -void AutoSizedWidget::notifySizeChange (MyGUI::Widget* w) -{ - if (w->getParent () != 0) - { - Box* b = dynamic_cast(w->getParent()); - if (b) - b->notifyChildrenSizeChanged (); - else + void MWSkill::setSkillValue(const SkillValue& value) { - if (mExpandDirection == MyGUI::Align::Left) + mValue = value; + updateWidgets(); + } + + void MWSkill::updateWidgets() + { + if (mSkillNameWidget) { - int hdiff = getRequestedSize ().width - w->getSize().width; - w->setPosition(w->getPosition() - MyGUI::IntPoint(hdiff, 0)); + if (mSkillId == ESM::Skill::Length) + { + static_cast(mSkillNameWidget)->setCaption(""); + } + else + { + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); + static_cast(mSkillNameWidget)->setCaption(name); + } + } + if (mSkillValueWidget) + { + SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); + static_cast(mSkillValueWidget)->setCaption(boost::lexical_cast(modified)); + if (modified > base) + mSkillValueWidget->_setWidgetState("increased"); + else if (modified < base) + mSkillValueWidget->_setWidgetState("decreased"); + else + mSkillValueWidget->_setWidgetState("normal"); } - w->setSize(getRequestedSize ()); } - } -} - -MyGUI::IntSize AutoSizedTextBox::getRequestedSize() -{ - return getTextSize(); -} - -void AutoSizedTextBox::setCaption(const MyGUI::UString& _value) -{ - TextBox::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - TextBox::setPropertyOverride (_key, _value); - } -} - -MyGUI::IntSize AutoSizedEditBox::getRequestedSize() -{ - if (getAlign().isHStretch()) - throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")"); - return MyGUI::IntSize(getSize().width, getTextSize().height); -} - -void AutoSizedEditBox::setCaption(const MyGUI::UString& _value) -{ - EditBox::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - EditBox::setPropertyOverride (_key, _value); - } -} - - -MyGUI::IntSize AutoSizedButton::getRequestedSize() -{ - MyGUI::IntSize size = getTextSize() + MyGUI::IntSize(24,0); - size.height = std::max(24, size.height); - return size; -} - -void AutoSizedButton::setCaption(const MyGUI::UString& _value) -{ - Button::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedButton::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - Button::setPropertyOverride (_key, _value); - } -} - -Box::Box() - : mSpacing(4) - , mPadding(0) - , mAutoResize(false) -{ - -} - -void Box::notifyChildrenSizeChanged () -{ - align(); -} - -void Box::_setPropertyImpl(const std::string& _key, const std::string& _value) -{ - if (_key == "Spacing") - mSpacing = MyGUI::utility::parseValue(_value); - else if (_key == "Padding") - mPadding = MyGUI::utility::parseValue(_value); - else if (_key == "AutoResize") - mAutoResize = MyGUI::utility::parseValue(_value); -} - -void HBox::align () -{ - unsigned int count = getChildCount (); - size_t h_stretched_count = 0; - int total_width = 0; - int total_height = 0; - std::vector< std::pair > sizes; - - for (unsigned int i = 0; i < count; ++i) - { - MyGUI::Widget* w = getChildAt(i); - bool hstretch = w->getUserString ("HStretch") == "true"; - h_stretched_count += hstretch; - AutoSizedWidget* aw = dynamic_cast(w); - if (aw) + void MWSkill::onClicked(MyGUI::Widget* _sender) { - sizes.push_back(std::make_pair(aw->getRequestedSize (), hstretch)); - total_width += aw->getRequestedSize ().width; - total_height = std::max(total_height, aw->getRequestedSize ().height); + eventClicked(this); } - else + + MWSkill::~MWSkill() { - sizes.push_back (std::make_pair(w->getSize(), hstretch)); - total_width += w->getSize().width; - if (!(w->getUserString("VStretch") == "true")) - total_height = std::max(total_height, w->getSize().height); } - if (i != count-1) - total_width += mSpacing; - } - - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) - { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); - return; - } - - - int curX = 0; - for (unsigned int i = 0; i < count; ++i) - { - if (i == 0) - curX += mPadding; - - MyGUI::Widget* w = getChildAt(i); - - bool vstretch = w->getUserString ("VStretch") == "true"; - int height = vstretch ? total_height : sizes[i].first.height; - - MyGUI::IntCoord widgetCoord; - widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; - int width = sizes[i].second ? sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count - : sizes[i].first.width; - widgetCoord.width = width; - widgetCoord.height = height; - w->setCoord(widgetCoord); - curX += width; - - if (i != count-1) - curX += mSpacing; - } -} - -void HBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - Box::_setPropertyImpl (_key, _value); -} - -void HBox::setSize (const MyGUI::IntSize& _value) -{ - MyGUI::Widget::setSize (_value); - align(); -} - -void HBox::setCoord (const MyGUI::IntCoord& _value) -{ - MyGUI::Widget::setCoord (_value); - align(); -} - -void HBox::onWidgetCreated(MyGUI::Widget* _widget) -{ - align(); -} - -MyGUI::IntSize HBox::getRequestedSize () -{ - MyGUI::IntSize size(0,0); - for (unsigned int i = 0; i < getChildCount (); ++i) - { - AutoSizedWidget* w = dynamic_cast(getChildAt(i)); - if (w) + void MWSkill::initialiseOverride() { - MyGUI::IntSize requested = w->getRequestedSize (); - size.height = std::max(size.height, requested.height); - size.width = size.width + requested.width; - if (i != getChildCount()-1) - size.width += mSpacing; + Base::initialiseOverride(); + + assignWidget(mSkillNameWidget, "StatName"); + assignWidget(mSkillValueWidget, "StatValue"); + + MyGUI::Button* button; + assignWidget(button, "StatNameButton"); + if (button) + { + mSkillNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); + } + + button = 0; + assignWidget(button, "StatValueButton"); + if (button) + { + mSkillNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); + } } - else + + /* MWAttribute */ + + MWAttribute::MWAttribute() + : mId(-1) + , mAttributeNameWidget(NULL) + , mAttributeValueWidget(NULL) { - MyGUI::IntSize requested = getChildAt(i)->getSize (); - size.height = std::max(size.height, requested.height); - - if (getChildAt(i)->getUserString("HStretch") != "true") - size.width = size.width + requested.width; - - if (i != getChildCount()-1) - size.width += mSpacing; } - size.height += mPadding*2; - size.width += mPadding*2; - } - return size; -} - - - -void VBox::align () -{ - unsigned int count = getChildCount (); - size_t v_stretched_count = 0; - int total_height = 0; - int total_width = 0; - std::vector< std::pair > sizes; - for (unsigned int i = 0; i < count; ++i) - { - MyGUI::Widget* w = getChildAt(i); - bool vstretch = w->getUserString ("VStretch") == "true"; - v_stretched_count += vstretch; - AutoSizedWidget* aw = dynamic_cast(w); - if (aw) + void MWAttribute::setAttributeId(int attributeId) { - sizes.push_back(std::make_pair(aw->getRequestedSize (), vstretch)); - total_height += aw->getRequestedSize ().height; - total_width = std::max(total_width, aw->getRequestedSize ().width); + mId = attributeId; + updateWidgets(); } - else + + void MWAttribute::setAttributeValue(const AttributeValue& value) { - sizes.push_back (std::make_pair(w->getSize(), vstretch)); - total_height += w->getSize().height; - - if (!(w->getUserString("HStretch") == "true")) - total_width = std::max(total_width, w->getSize().width); + mValue = value; + updateWidgets(); } - if (i != count-1) - total_height += mSpacing; - } + void MWAttribute::onClicked(MyGUI::Widget* _sender) + { + eventClicked(this); + } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) - { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); - return; - } + void MWAttribute::updateWidgets() + { + if (mAttributeNameWidget) + { + if (mId < 0 || mId >= 8) + { + static_cast(mAttributeNameWidget)->setCaption(""); + } + else + { + static const char *attributes[8] = { + "sAttributeStrength", + "sAttributeIntelligence", + "sAttributeWillpower", + "sAttributeAgility", + "sAttributeSpeed", + "sAttributeEndurance", + "sAttributePersonality", + "sAttributeLuck" + }; + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); + static_cast(mAttributeNameWidget)->setCaption(name); + } + } + if (mAttributeValueWidget) + { + AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); + static_cast(mAttributeValueWidget)->setCaption(boost::lexical_cast(modified)); + if (modified > base) + mAttributeValueWidget->_setWidgetState("increased"); + else if (modified < base) + mAttributeValueWidget->_setWidgetState("decreased"); + else + mAttributeValueWidget->_setWidgetState("normal"); + } + } + + MWAttribute::~MWAttribute() + { + } + + void MWAttribute::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mAttributeNameWidget, "StatName"); + assignWidget(mAttributeValueWidget, "StatValue"); + + MyGUI::Button* button; + assignWidget(button, "StatNameButton"); + if (button) + { + mAttributeNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); + } + + button = 0; + assignWidget(button, "StatValueButton"); + if (button) + { + mAttributeValueWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); + } + } + + /* MWSpell */ + + MWSpell::MWSpell() + : mSpellNameWidget(NULL) + { + } + + void MWSpell::setSpellId(const std::string &spellId) + { + mId = spellId; + updateWidgets(); + } + + void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell *spell = store.get().search(mId); + MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); + + MWSpellEffectPtr effect = NULL; + std::vector::const_iterator end = spell->mEffects.mList.end(); + for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + { + effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); + SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + params.mIsConstant = (flags & MWEffectList::EF_Constant); + params.mNoTarget = (flags & MWEffectList::EF_NoTarget); + effect->setSpellEffect(params); + effects.push_back(effect); + coord.top += effect->getHeight(); + coord.width = std::max(coord.width, effect->getRequestedWidth()); + } + } + + void MWSpell::updateWidgets() + { + if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell *spell = store.get().search(mId); + if (spell) + static_cast(mSpellNameWidget)->setCaption(spell->mName); + else + static_cast(mSpellNameWidget)->setCaption(""); + } + } + + void MWSpell::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mSpellNameWidget, "StatName"); + } + + MWSpell::~MWSpell() + { + } + + /* MWEffectList */ + + MWEffectList::MWEffectList() + : mEffectList(0) + { + } + + void MWEffectList::setEffectList(const SpellEffectList& list) + { + mEffectList = list; + updateWidgets(); + } + + void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, bool center, int flags) + { + // We don't know the width of all the elements beforehand, so we do it in + // 2 steps: first, create all widgets and check their width.... + MWSpellEffectPtr effect = NULL; + int maxwidth = coord.width; + + for (SpellEffectList::iterator it=mEffectList.begin(); + it != mEffectList.end(); ++it) + { + effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); + it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; + it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; + effect->setSpellEffect(*it); + effects.push_back(effect); + if (effect->getRequestedWidth() > maxwidth) + maxwidth = effect->getRequestedWidth(); + + coord.top += effect->getHeight(); + } + + // ... then adjust the size for all widgets + for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) + { + effect = static_cast(*it); + bool needcenter = center && (maxwidth > effect->getRequestedWidth()); + int diff = maxwidth - effect->getRequestedWidth(); + if (needcenter) + { + effect->setCoord(diff/2, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); + } + else + { + effect->setCoord(0, effect->getCoord().top, effect->getRequestedWidth(), effect->getCoord().height); + } + } + + // inform the parent about width + coord.width = maxwidth; + } + + void MWEffectList::updateWidgets() + { + } + + void MWEffectList::initialiseOverride() + { + Base::initialiseOverride(); + } + + MWEffectList::~MWEffectList() + { + } + + SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) + { + SpellEffectList result; + std::vector::const_iterator end = effects->mList.end(); + for (std::vector::const_iterator it = effects->mList.begin(); it != end; ++it) + { + SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + params.mArea = it->mArea; + result.push_back(params); + } + return result; + } + + /* MWSpellEffect */ + + MWSpellEffect::MWSpellEffect() + : mImageWidget(NULL) + , mTextWidget(NULL) + , mRequestedWidth(0) + { + } + + void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) + { + mEffectParams = params; + updateWidgets(); + } + + void MWSpellEffect::updateWidgets() + { + if (!mEffectParams.mKnown) + { + mTextWidget->setCaption ("?"); + mRequestedWidth = mTextWidget->getTextSize().width + 24; + mImageWidget->setImageTexture (""); + return; + } + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::MagicEffect *magicEffect = + store.get().search(mEffectParams.mEffectID); + + assert(magicEffect); + + std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); + std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; + std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); + std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); + + std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); + std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); + + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); + } + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); + } + + if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) + { + if (mEffectParams.mMagnMin == mEffectParams.mMagnMax) + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts); + else + { + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + to + boost::lexical_cast(mEffectParams.mMagnMax) + " " + pts; + } + } + + // constant effects have no duration and no target + if (!mEffectParams.mIsConstant) + { + if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + } + + if (mEffectParams.mArea > 0) + { + spellLine += " #{sin} " + boost::lexical_cast(mEffectParams.mArea) + " #{sfootarea}"; + } + + // potions have no target + if (!mEffectParams.mNoTarget) + { + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); + if (mEffectParams.mRange == ESM::RT_Self) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); + else if (mEffectParams.mRange == ESM::RT_Touch) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); + else if (mEffectParams.mRange == ESM::RT_Target) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); + } + } + + static_cast(mTextWidget)->setCaptionWithReplacing(spellLine); + mRequestedWidth = mTextWidget->getTextSize().width + 24; + + std::string path = std::string("icons\\") + magicEffect->mIcon; + fixTexturePath(path); + mImageWidget->setImageTexture(path); + } + + MWSpellEffect::~MWSpellEffect() + { + } + + void MWSpellEffect::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mTextWidget, "Text"); + assignWidget(mImageWidget, "Image"); + } + + /* MWDynamicStat */ + + MWDynamicStat::MWDynamicStat() + : mValue(0) + , mMax(1) + , mTextWidget(NULL) + , mBarWidget(NULL) + , mBarTextWidget(NULL) + { + } + + void MWDynamicStat::setValue(int cur, int max) + { + mValue = cur; + mMax = max; + + if (mBarWidget) + { + mBarWidget->setProgressRange(mMax); + mBarWidget->setProgressPosition(mValue); + } - int curY = 0; - for (unsigned int i = 0; i < count; ++i) - { - if (i==0) - curY += mPadding; + if (mBarTextWidget) + { + if (mValue >= 0 && mMax > 0) + { + std::stringstream out; + out << mValue << "/" << mMax; + static_cast(mBarTextWidget)->setCaption(out.str().c_str()); + } + else + static_cast(mBarTextWidget)->setCaption(""); + } + } + void MWDynamicStat::setTitle(const std::string& text) + { + if (mTextWidget) + static_cast(mTextWidget)->setCaption(text); + } - MyGUI::Widget* w = getChildAt(i); + MWDynamicStat::~MWDynamicStat() + { + } - bool hstretch = w->getUserString ("HStretch") == "true"; - int width = hstretch ? total_width : sizes[i].first.width; + void MWDynamicStat::initialiseOverride() + { + Base::initialiseOverride(); - MyGUI::IntCoord widgetCoord; - widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; - int height = sizes[i].second ? sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count - : sizes[i].first.height; - widgetCoord.height = height; - widgetCoord.width = width; - w->setCoord(widgetCoord); - curY += height; + assignWidget(mTextWidget, "Text"); + assignWidget(mBarWidget, "Bar"); + assignWidget(mBarTextWidget, "BarText"); + } - if (i != count-1) - curY += mSpacing; + + + + // --------------------------------------------------------------------------------------------------------------------- + + void AutoSizedWidget::notifySizeChange (MyGUI::Widget* w) + { + if (w->getParent () != 0) + { + Box* b = dynamic_cast(w->getParent()); + if (b) + b->notifyChildrenSizeChanged (); + else + { + if (mExpandDirection == MyGUI::Align::Left) + { + int hdiff = getRequestedSize ().width - w->getSize().width; + w->setPosition(w->getPosition() - MyGUI::IntPoint(hdiff, 0)); + } + w->setSize(getRequestedSize ()); + } + } + } + + + MyGUI::IntSize AutoSizedTextBox::getRequestedSize() + { + return getTextSize(); + } + + void AutoSizedTextBox::setCaption(const MyGUI::UString& _value) + { + TextBox::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + TextBox::setPropertyOverride (_key, _value); + } + } + + MyGUI::IntSize AutoSizedEditBox::getRequestedSize() + { + if (getAlign().isHStretch()) + throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")"); + return MyGUI::IntSize(getSize().width, getTextSize().height); + } + + void AutoSizedEditBox::setCaption(const MyGUI::UString& _value) + { + EditBox::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + EditBox::setPropertyOverride (_key, _value); + } + } + + + MyGUI::IntSize AutoSizedButton::getRequestedSize() + { + MyGUI::IntSize size = getTextSize() + MyGUI::IntSize(24,0); + size.height = std::max(24, size.height); + return size; + } + + void AutoSizedButton::setCaption(const MyGUI::UString& _value) + { + Button::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedButton::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + Button::setPropertyOverride (_key, _value); + } + } + + Box::Box() + : mSpacing(4) + , mPadding(0) + , mAutoResize(false) + { + + } + + void Box::notifyChildrenSizeChanged () + { + align(); + } + + void Box::_setPropertyImpl(const std::string& _key, const std::string& _value) + { + if (_key == "Spacing") + mSpacing = MyGUI::utility::parseValue(_value); + else if (_key == "Padding") + mPadding = MyGUI::utility::parseValue(_value); + else if (_key == "AutoResize") + mAutoResize = MyGUI::utility::parseValue(_value); + } + + void HBox::align () + { + unsigned int count = getChildCount (); + size_t h_stretched_count = 0; + int total_width = 0; + int total_height = 0; + std::vector< std::pair > sizes; + + for (unsigned int i = 0; i < count; ++i) + { + MyGUI::Widget* w = getChildAt(i); + bool hstretch = w->getUserString ("HStretch") == "true"; + h_stretched_count += hstretch; + AutoSizedWidget* aw = dynamic_cast(w); + if (aw) + { + sizes.push_back(std::make_pair(aw->getRequestedSize (), hstretch)); + total_width += aw->getRequestedSize ().width; + total_height = std::max(total_height, aw->getRequestedSize ().height); + } + else + { + sizes.push_back (std::make_pair(w->getSize(), hstretch)); + total_width += w->getSize().width; + if (!(w->getUserString("VStretch") == "true")) + total_height = std::max(total_height, w->getSize().height); + } + + if (i != count-1) + total_width += mSpacing; + } + + if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + { + setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + return; + } + + + int curX = 0; + for (unsigned int i = 0; i < count; ++i) + { + if (i == 0) + curX += mPadding; + + MyGUI::Widget* w = getChildAt(i); + + bool vstretch = w->getUserString ("VStretch") == "true"; + int height = vstretch ? total_height : sizes[i].first.height; + + MyGUI::IntCoord widgetCoord; + widgetCoord.left = curX; + widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + int width = sizes[i].second ? sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count + : sizes[i].first.width; + widgetCoord.width = width; + widgetCoord.height = height; + w->setCoord(widgetCoord); + curX += width; + + if (i != count-1) + curX += mSpacing; + } + } + + void HBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + Box::_setPropertyImpl (_key, _value); + } + + void HBox::setSize (const MyGUI::IntSize& _value) + { + MyGUI::Widget::setSize (_value); + align(); + } + + void HBox::setCoord (const MyGUI::IntCoord& _value) + { + MyGUI::Widget::setCoord (_value); + align(); + } + + void HBox::onWidgetCreated(MyGUI::Widget* _widget) + { + align(); + } + + MyGUI::IntSize HBox::getRequestedSize () + { + MyGUI::IntSize size(0,0); + for (unsigned int i = 0; i < getChildCount (); ++i) + { + AutoSizedWidget* w = dynamic_cast(getChildAt(i)); + if (w) + { + MyGUI::IntSize requested = w->getRequestedSize (); + size.height = std::max(size.height, requested.height); + size.width = size.width + requested.width; + if (i != getChildCount()-1) + size.width += mSpacing; + } + else + { + MyGUI::IntSize requested = getChildAt(i)->getSize (); + size.height = std::max(size.height, requested.height); + + if (getChildAt(i)->getUserString("HStretch") != "true") + size.width = size.width + requested.width; + + if (i != getChildCount()-1) + size.width += mSpacing; + } + size.height += mPadding*2; + size.width += mPadding*2; + } + return size; + } + + + + + void VBox::align () + { + unsigned int count = getChildCount (); + size_t v_stretched_count = 0; + int total_height = 0; + int total_width = 0; + std::vector< std::pair > sizes; + for (unsigned int i = 0; i < count; ++i) + { + MyGUI::Widget* w = getChildAt(i); + bool vstretch = w->getUserString ("VStretch") == "true"; + v_stretched_count += vstretch; + AutoSizedWidget* aw = dynamic_cast(w); + if (aw) + { + sizes.push_back(std::make_pair(aw->getRequestedSize (), vstretch)); + total_height += aw->getRequestedSize ().height; + total_width = std::max(total_width, aw->getRequestedSize ().width); + } + else + { + sizes.push_back (std::make_pair(w->getSize(), vstretch)); + total_height += w->getSize().height; + + if (!(w->getUserString("HStretch") == "true")) + total_width = std::max(total_width, w->getSize().width); + } + + if (i != count-1) + total_height += mSpacing; + } + + if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + { + setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + return; + } + + + int curY = 0; + for (unsigned int i = 0; i < count; ++i) + { + if (i==0) + curY += mPadding; + + MyGUI::Widget* w = getChildAt(i); + + bool hstretch = w->getUserString ("HStretch") == "true"; + int width = hstretch ? total_width : sizes[i].first.width; + + MyGUI::IntCoord widgetCoord; + widgetCoord.top = curY; + widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + int height = sizes[i].second ? sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count + : sizes[i].first.height; + widgetCoord.height = height; + widgetCoord.width = width; + w->setCoord(widgetCoord); + curY += height; + + if (i != count-1) + curY += mSpacing; + } + } + + void VBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + Box::_setPropertyImpl (_key, _value); + } + + void VBox::setSize (const MyGUI::IntSize& _value) + { + MyGUI::Widget::setSize (_value); + align(); + } + + void VBox::setCoord (const MyGUI::IntCoord& _value) + { + MyGUI::Widget::setCoord (_value); + align(); + } + + MyGUI::IntSize VBox::getRequestedSize () + { + MyGUI::IntSize size(0,0); + for (unsigned int i = 0; i < getChildCount (); ++i) + { + AutoSizedWidget* w = dynamic_cast(getChildAt(i)); + if (w) + { + MyGUI::IntSize requested = w->getRequestedSize (); + size.width = std::max(size.width, requested.width); + size.height = size.height + requested.height; + if (i != getChildCount()-1) + size.height += mSpacing; + } + else + { + MyGUI::IntSize requested = getChildAt(i)->getSize (); + size.width = std::max(size.width, requested.width); + + if (getChildAt(i)->getUserString("VStretch") != "true") + size.height = size.height + requested.height; + + if (i != getChildCount()-1) + size.height += mSpacing; + } + size.height += mPadding*2; + size.width += mPadding*2; + } + return size; + } + + void VBox::onWidgetCreated(MyGUI::Widget* _widget) + { + align(); + } } } - -void VBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - Box::_setPropertyImpl (_key, _value); -} - -void VBox::setSize (const MyGUI::IntSize& _value) -{ - MyGUI::Widget::setSize (_value); - align(); -} - -void VBox::setCoord (const MyGUI::IntCoord& _value) -{ - MyGUI::Widget::setCoord (_value); - align(); -} - -MyGUI::IntSize VBox::getRequestedSize () -{ - MyGUI::IntSize size(0,0); - for (unsigned int i = 0; i < getChildCount (); ++i) - { - AutoSizedWidget* w = dynamic_cast(getChildAt(i)); - if (w) - { - MyGUI::IntSize requested = w->getRequestedSize (); - size.width = std::max(size.width, requested.width); - size.height = size.height + requested.height; - if (i != getChildCount()-1) - size.height += mSpacing; - } - else - { - MyGUI::IntSize requested = getChildAt(i)->getSize (); - size.width = std::max(size.width, requested.width); - - if (getChildAt(i)->getUserString("VStretch") != "true") - size.height = size.height + requested.height; - - if (i != getChildCount()-1) - size.height += mSpacing; - } - size.height += mPadding*2; - size.width += mPadding*2; - } - return size; -} - -void VBox::onWidgetCreated(MyGUI::Widget* _widget) -{ - align(); -} diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 154234bee..2171beaff 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -39,1143 +39,1146 @@ #include "companionwindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; - -WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *ogre, - const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage) - : mGuiManager(NULL) - , mRendering(ogre) - , mHud(NULL) - , mMap(NULL) - , mMenu(NULL) - , mStatsWindow(NULL) - , mToolTips(NULL) - , mMessageBoxManager(NULL) - , mConsole(NULL) - , mJournal(NULL) - , mDialogueWindow(NULL) - , mBookWindow(NULL) - , mScrollWindow(NULL) - , mCountDialog(NULL) - , mTradeWindow(NULL) - , mSpellBuyingWindow(NULL) - , mTravelWindow(NULL) - , mSettingsWindow(NULL) - , mConfirmationDialog(NULL) - , mAlchemyWindow(NULL) - , mSpellWindow(NULL) - , mLoadingScreen(NULL) - , mCharGen(NULL) - , mLevelupDialog(NULL) - , mWaitDialog(NULL) - , mSpellCreationDialog(NULL) - , mEnchantingDialog(NULL) - , mTrainingWindow(NULL) - , mMerchantRepair(NULL) - , mRepair(NULL) - , mSoulgemDialog(NULL) - , mCompanionWindow(NULL) - , mPlayerName() - , mPlayerRaceId() - , mPlayerAttributes() - , mPlayerMajorSkills() - , mPlayerMinorSkills() - , mPlayerSkillValues() - , mPlayerHealth() - , mPlayerMagicka() - , mPlayerFatigue() - , mGui(NULL) - , mGarbageDialogs() - , mShown(GW_ALL) - , mAllowed(newGame ? GW_None : GW_ALL) - , mRestAllowed(newGame ? false : true) - , mShowFPSLevel(fpsLevel) - , mFPS(0.0f) - , mTriangleCount(0) - , mBatchCount(0) - , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) - , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) - , mHudEnabled(true) - , mTranslationDataStorage (translationDataStorage) +namespace MWGui { - // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); - mGui = mGuiManager->getGui(); - //Register own widgets with MyGUI - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - - MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); - MyGUI::ResourceManager::getInstance().load("core.xml"); - - MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); - - // Get size info from the Gui object - assert(mGui); - int w = MyGUI::RenderManager::getInstance().getViewSize().width; - int h = MyGUI::RenderManager::getInstance().getViewSize().height; - - MyGUI::Widget* dragAndDropWidget = mGui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); - dragAndDropWidget->setVisible(false); - - mDragAndDrop = new DragAndDrop(); - mDragAndDrop->mIsOnDragAndDrop = false; - mDragAndDrop->mDraggedWidget = 0; - mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - - mMenu = new MainMenu(w,h); - mMap = new MapWindow(cacheDir); - mStatsWindow = new StatsWindow(); - mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(); - mMessageBoxManager = new MessageBoxManager(); - mInventoryWindow = new InventoryWindow(mDragAndDrop); - mTradeWindow = new TradeWindow(); - mSpellBuyingWindow = new SpellBuyingWindow(); - mTravelWindow = new TravelWindow(); - mDialogueWindow = new DialogueWindow(); - mContainerWindow = new ContainerWindow(mDragAndDrop); - mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); - mToolTips = new ToolTips(); - mScrollWindow = new ScrollWindow(); - mBookWindow = new BookWindow(); - mCountDialog = new CountDialog(); - mSettingsWindow = new SettingsWindow(); - mConfirmationDialog = new ConfirmationDialog(); - mAlchemyWindow = new AlchemyWindow(); - mSpellWindow = new SpellWindow(); - mQuickKeysMenu = new QuickKeysMenu(); - mLevelupDialog = new LevelupDialog(); - mWaitDialog = new WaitDialog(); - mSpellCreationDialog = new SpellCreationDialog(); - mEnchantingDialog = new EnchantingDialog(); - mTrainingWindow = new TrainingWindow(); - mMerchantRepair = new MerchantRepair(); - mRepair = new Repair(); - mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); - mLoadingScreen->onResChange (w,h); - - mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); - - mCursor = new Cursor(); - - mHud->setVisible(mHudEnabled); - - mCharGen = new CharacterCreation(); - - // Setup player stats - for (int i = 0; i < ESM::Attribute::Length; ++i) + WindowManager::WindowManager( + const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *ogre, + const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + Translation::Storage& translationDataStorage) + : mGuiManager(NULL) + , mRendering(ogre) + , mHud(NULL) + , mMap(NULL) + , mMenu(NULL) + , mStatsWindow(NULL) + , mToolTips(NULL) + , mMessageBoxManager(NULL) + , mConsole(NULL) + , mJournal(NULL) + , mDialogueWindow(NULL) + , mBookWindow(NULL) + , mScrollWindow(NULL) + , mCountDialog(NULL) + , mTradeWindow(NULL) + , mSpellBuyingWindow(NULL) + , mTravelWindow(NULL) + , mSettingsWindow(NULL) + , mConfirmationDialog(NULL) + , mAlchemyWindow(NULL) + , mSpellWindow(NULL) + , mLoadingScreen(NULL) + , mCharGen(NULL) + , mLevelupDialog(NULL) + , mWaitDialog(NULL) + , mSpellCreationDialog(NULL) + , mEnchantingDialog(NULL) + , mTrainingWindow(NULL) + , mMerchantRepair(NULL) + , mRepair(NULL) + , mSoulgemDialog(NULL) + , mCompanionWindow(NULL) + , mPlayerName() + , mPlayerRaceId() + , mPlayerAttributes() + , mPlayerMajorSkills() + , mPlayerMinorSkills() + , mPlayerSkillValues() + , mPlayerHealth() + , mPlayerMagicka() + , mPlayerFatigue() + , mGui(NULL) + , mGarbageDialogs() + , mShown(GW_ALL) + , mAllowed(newGame ? GW_None : GW_ALL) + , mRestAllowed(newGame ? false : true) + , mShowFPSLevel(fpsLevel) + , mFPS(0.0f) + , mTriangleCount(0) + , mBatchCount(0) + , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) + , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) + , mHudEnabled(true) + , mTranslationDataStorage (translationDataStorage) { - mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat())); - } + // Set up the GUI system + mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); + mGui = mGuiManager->getGui(); - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat())); - } + //Register own widgets with MyGUI + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); - unsetSelectedSpell(); - unsetSelectedWeapon(); + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + MyGUI::ResourceManager::getInstance().load("core.xml"); - if (newGame) - disallowAll (); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); - // Set up visibility - updateVisible(); -} + // Get size info from the Gui object + assert(mGui); + int w = MyGUI::RenderManager::getInstance().getViewSize().width; + int h = MyGUI::RenderManager::getInstance().getViewSize().height; -WindowManager::~WindowManager() -{ - delete mConsole; - delete mMessageBoxManager; - delete mHud; - delete mMap; - delete mMenu; - delete mStatsWindow; - delete mJournal; - delete mDialogueWindow; - delete mContainerWindow; - delete mInventoryWindow; - delete mToolTips; - delete mCharGen; - delete mDragAndDrop; - delete mBookWindow; - delete mScrollWindow; - delete mTradeWindow; - delete mSpellBuyingWindow; - delete mTravelWindow; - delete mSettingsWindow; - delete mConfirmationDialog; - delete mAlchemyWindow; - delete mSpellWindow; - delete mLoadingScreen; - delete mLevelupDialog; - delete mWaitDialog; - delete mSpellCreationDialog; - delete mEnchantingDialog; - delete mTrainingWindow; - delete mCountDialog; - delete mQuickKeysMenu; - delete mMerchantRepair; - delete mRepair; - delete mSoulgemDialog; - delete mCursor; + MyGUI::Widget* dragAndDropWidget = mGui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); + dragAndDropWidget->setVisible(false); - cleanupGarbage(); + mDragAndDrop = new DragAndDrop(); + mDragAndDrop->mIsOnDragAndDrop = false; + mDragAndDrop->mDraggedWidget = 0; + mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - delete mGuiManager; -} + mMenu = new MainMenu(w,h); + mMap = new MapWindow(cacheDir); + mStatsWindow = new StatsWindow(); + mConsole = new Console(w,h, consoleOnlyScripts); + mJournal = new JournalWindow(); + mMessageBoxManager = new MessageBoxManager(); + mInventoryWindow = new InventoryWindow(mDragAndDrop); + mTradeWindow = new TradeWindow(); + mSpellBuyingWindow = new SpellBuyingWindow(); + mTravelWindow = new TravelWindow(); + mDialogueWindow = new DialogueWindow(); + mContainerWindow = new ContainerWindow(mDragAndDrop); + mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mBookWindow = new BookWindow(); + mCountDialog = new CountDialog(); + mSettingsWindow = new SettingsWindow(); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); + mSpellWindow = new SpellWindow(); + mQuickKeysMenu = new QuickKeysMenu(); + mLevelupDialog = new LevelupDialog(); + mWaitDialog = new WaitDialog(); + mSpellCreationDialog = new SpellCreationDialog(); + mEnchantingDialog = new EnchantingDialog(); + mTrainingWindow = new TrainingWindow(); + mMerchantRepair = new MerchantRepair(); + mRepair = new Repair(); + mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); -void WindowManager::cleanupGarbage() -{ - // Delete any dialogs which are no longer in use - if (!mGarbageDialogs.empty()) - { - for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); + mLoadingScreen->onResChange (w,h); + + mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + + mCursor = new Cursor(); + + mHud->setVisible(mHudEnabled); + + mCharGen = new CharacterCreation(); + + // Setup player stats + for (int i = 0; i < ESM::Attribute::Length; ++i) { - delete *it; + mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat())); } - mGarbageDialogs.clear(); - } -} -void WindowManager::update() -{ - cleanupGarbage(); - - mHud->setFPS(mFPS); - mHud->setTriangleCount(mTriangleCount); - mHud->setBatchCount(mBatchCount); - - mHud->update(); - - mCursor->update(); -} - -void WindowManager::updateVisible() -{ - // Start out by hiding everything except the HUD - mMap->setVisible(false); - mMenu->setVisible(false); - mStatsWindow->setVisible(false); - mConsole->disable(); - mJournal->setVisible(false); - mDialogueWindow->setVisible(false); - mContainerWindow->setVisible(false); - mInventoryWindow->setVisible(false); - mScrollWindow->setVisible(false); - mBookWindow->setVisible(false); - mTradeWindow->setVisible(false); - mSpellBuyingWindow->setVisible(false); - mTravelWindow->setVisible(false); - mSettingsWindow->setVisible(false); - mAlchemyWindow->setVisible(false); - mSpellWindow->setVisible(false); - mQuickKeysMenu->setVisible(false); - mLevelupDialog->setVisible(false); - mWaitDialog->setVisible(false); - mSpellCreationDialog->setVisible(false); - mEnchantingDialog->setVisible(false); - mTrainingWindow->setVisible(false); - mMerchantRepair->setVisible(false); - mRepair->setVisible(false); - mCompanionWindow->setVisible(false); - - mHud->setVisible(mHudEnabled); - - bool gameMode = !isGuiMode(); - - mInputBlocker->setVisible (gameMode); - - if (gameMode) - mToolTips->enterGameMode(); - else - mToolTips->enterGuiMode(); - - if (gameMode) - MyGUI::InputManager::getInstance ().setKeyFocusWidget (NULL); - - setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); - setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); - setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); - setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); - - // If in game mode, show only the pinned windows - if (gameMode) - { - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - - return; - } - - GuiMode mode = mGuiModes.back(); - - switch(mode) { - case GM_QuickKeysMenu: - mQuickKeysMenu->setVisible (true); - break; - case GM_MainMenu: - mMenu->setVisible(true); - break; - case GM_Settings: - mSettingsWindow->setVisible(true); - break; - case GM_Console: - // Show the pinned windows - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - - mConsole->enable(); - break; - case GM_Scroll: - mScrollWindow->setVisible(true); - break; - case GM_Book: - mBookWindow->setVisible(true); - break; - case GM_Alchemy: - mAlchemyWindow->setVisible(true); - break; - case GM_Rest: - mWaitDialog->setVisible(true); - break; - case GM_RestBed: - mWaitDialog->setVisible(true); - mWaitDialog->bedActivated(); - break; - case GM_Levelup: - mLevelupDialog->setVisible(true); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - mCharGen->spawnDialog(mode); - break; - case GM_Inventory: + for (int i = 0; i < ESM::Skill::Length; ++i) { - // First, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed; - - // Show the windows we want - mMap ->setVisible(eff & GW_Map); - mStatsWindow ->setVisible(eff & GW_Stats); - mInventoryWindow->setVisible(eff & GW_Inventory); - mSpellWindow ->setVisible(eff & GW_Magic); - break; + mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat())); } - case GM_Container: - mContainerWindow->setVisible(true); - mInventoryWindow->setVisible(true); - break; - case GM_Companion: - mCompanionWindow->setVisible(true); - mInventoryWindow->setVisible(true); - break; - case GM_Dialogue: - mDialogueWindow->setVisible(true); - break; - case GM_Barter: - mInventoryWindow->setVisible(true); - mTradeWindow->setVisible(true); - break; - case GM_SpellBuying: - mSpellBuyingWindow->setVisible(true); - break; - case GM_Travel: - mTravelWindow->setVisible(true); - break; - case GM_SpellCreation: - mSpellCreationDialog->setVisible(true); - break; - case GM_Enchanting: - mEnchantingDialog->setVisible(true); - break; - case GM_Training: - mTrainingWindow->setVisible(true); - break; - case GM_MerchantRepair: - mMerchantRepair->setVisible(true); - break; - case GM_Repair: - mRepair->setVisible(true); - break; - case GM_Journal: - mJournal->setVisible(true); - break; - case GM_LoadingWallpaper: - mHud->setVisible(false); - mCursor->setVisible(false); - break; - case GM_Loading: - // Show the pinned windows - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - mCursor->setVisible(false); - break; - case GM_Video: - mCursor->setVisible(false); - mHud->setVisible(false); - break; - default: - // Unsupported mode, switch back to game - break; - } -} + unsetSelectedSpell(); + unsetSelectedWeapon(); -void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - mStatsWindow->setValue (id, value); - mCharGen->setValue(id, value); + if (newGame) + disallowAll (); - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8" - }; - static ESM::Attribute::AttributeID attributes[] = - { - ESM::Attribute::Strength, - ESM::Attribute::Intelligence, - ESM::Attribute::Willpower, - ESM::Attribute::Agility, - ESM::Attribute::Speed, - ESM::Attribute::Endurance, - ESM::Attribute::Personality, - ESM::Attribute::Luck - }; - for (size_t i = 0; i < sizeof(ids)/sizeof(ids[0]); ++i) - { - if (id != ids[i]) - continue; - mPlayerAttributes[attributes[i]] = value; - break; - } -} - - -void WindowManager::setValue (int parSkill, const MWMechanics::Stat& value) -{ - /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we - /// allow custom skills. - mStatsWindow->setValue(static_cast (parSkill), value); - mCharGen->setValue(static_cast (parSkill), value); - mPlayerSkillValues[parSkill] = value; -} - -void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - mStatsWindow->setValue (id, value); - mHud->setValue (id, value); - mCharGen->setValue(id, value); - if (id == "HBar") - { - mPlayerHealth = value; - mCharGen->setPlayerHealth (value); - } - else if (id == "MBar") - { - mPlayerMagicka = value; - mCharGen->setPlayerMagicka (value); - } - else if (id == "FBar") - { - mPlayerFatigue = value; - mCharGen->setPlayerFatigue (value); - } -} - -#if 0 -MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) -{ - if(id == "HBar") - return layerHealth; - else if (id == "MBar") - return mPlayerMagicka; - else if (id == "FBar") - return mPlayerFatigue; -} -#endif - -void WindowManager::setValue (const std::string& id, const std::string& value) -{ - mStatsWindow->setValue (id, value); - if (id=="name") - mPlayerName = value; - else if (id=="race") - mPlayerRaceId = value; -} - -void WindowManager::setValue (const std::string& id, int value) -{ - mStatsWindow->setValue (id, value); -} - -void WindowManager::setPlayerClass (const ESM::Class &class_) -{ - mStatsWindow->setValue("class", class_.mName); -} - -void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) -{ - mStatsWindow->configureSkills (major, minor); - mCharGen->configureSkills(major, minor); - mPlayerMajorSkills = major; - mPlayerMinorSkills = minor; -} - -void WindowManager::setReputation (int reputation) -{ - mStatsWindow->setReputation (reputation); -} - -void WindowManager::setBounty (int bounty) -{ - mStatsWindow->setBounty (bounty); -} - -void WindowManager::updateSkillArea() -{ - mStatsWindow->updateSkillArea(); -} - -void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) -{ - if (!dialog) - return; - dialog->setVisible(false); - mGarbageDialogs.push_back(dialog); -} - -void WindowManager::messageBox (const std::string& message, const std::vector& buttons) -{ - if(buttons.empty()){ - /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ - if(!mGuiModes.empty() && mGuiModes.back() == GM_Dialogue) - mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); - else - mMessageBoxManager->createMessageBox(message); + // Set up visibility + updateVisible(); } - else + WindowManager::~WindowManager() { - mMessageBoxManager->createInteractiveMessageBox(message, buttons); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); + delete mConsole; + delete mMessageBoxManager; + delete mHud; + delete mMap; + delete mMenu; + delete mStatsWindow; + delete mJournal; + delete mDialogueWindow; + delete mContainerWindow; + delete mInventoryWindow; + delete mToolTips; + delete mCharGen; + delete mDragAndDrop; + delete mBookWindow; + delete mScrollWindow; + delete mTradeWindow; + delete mSpellBuyingWindow; + delete mTravelWindow; + delete mSettingsWindow; + delete mConfirmationDialog; + delete mAlchemyWindow; + delete mSpellWindow; + delete mLoadingScreen; + delete mLevelupDialog; + delete mWaitDialog; + delete mSpellCreationDialog; + delete mEnchantingDialog; + delete mTrainingWindow; + delete mCountDialog; + delete mQuickKeysMenu; + delete mMerchantRepair; + delete mRepair; + delete mSoulgemDialog; + delete mCursor; + + cleanupGarbage(); + + delete mGuiManager; } -} -void WindowManager::enterPressed () -{ - mMessageBoxManager->enterPressed(); -} - -int WindowManager::readPressedButton () -{ - return mMessageBoxManager->readPressedButton(); -} - -std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) -{ - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().search(id); - - if (setting && setting->mValue.getType()==ESM::VT_String) - return setting->mValue.getString(); - - return default_; -} - -void WindowManager::onDialogueWindowBye() -{ - if (mDialogueWindow) + void WindowManager::cleanupGarbage() { - //FIXME set some state and stuff? - //removeDialog(dialogueWindow); + // Delete any dialogs which are no longer in use + if (!mGarbageDialogs.empty()) + { + for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + { + delete *it; + } + mGarbageDialogs.clear(); + } + } + + void WindowManager::update() + { + cleanupGarbage(); + + mHud->setFPS(mFPS); + mHud->setTriangleCount(mTriangleCount); + mHud->setBatchCount(mBatchCount); + + mHud->update(); + + mCursor->update(); + } + + void WindowManager::updateVisible() + { + // Start out by hiding everything except the HUD + mMap->setVisible(false); + mMenu->setVisible(false); + mStatsWindow->setVisible(false); + mConsole->disable(); + mJournal->setVisible(false); mDialogueWindow->setVisible(false); - } - removeGuiMode(GM_Dialogue); -} + mContainerWindow->setVisible(false); + mInventoryWindow->setVisible(false); + mScrollWindow->setVisible(false); + mBookWindow->setVisible(false); + mTradeWindow->setVisible(false); + mSpellBuyingWindow->setVisible(false); + mTravelWindow->setVisible(false); + mSettingsWindow->setVisible(false); + mAlchemyWindow->setVisible(false); + mSpellWindow->setVisible(false); + mQuickKeysMenu->setVisible(false); + mLevelupDialog->setVisible(false); + mWaitDialog->setVisible(false); + mSpellCreationDialog->setVisible(false); + mEnchantingDialog->setVisible(false); + mTrainingWindow->setVisible(false); + mMerchantRepair->setVisible(false); + mRepair->setVisible(false); + mCompanionWindow->setVisible(false); -void WindowManager::onFrame (float frameDuration) -{ - mMessageBoxManager->onFrame(frameDuration); + mHud->setVisible(mHudEnabled); - mToolTips->onFrame(frameDuration); + bool gameMode = !isGuiMode(); - if (mDragAndDrop->mIsOnDragAndDrop) - { - assert(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - } + mInputBlocker->setVisible (gameMode); - mDialogueWindow->onFrame(); + if (gameMode) + mToolTips->enterGameMode(); + else + mToolTips->enterGuiMode(); - mInventoryWindow->onFrame(); + if (gameMode) + MyGUI::InputManager::getInstance ().setKeyFocusWidget (NULL); - mStatsWindow->onFrame(); + setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); + setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); + setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); + setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); - mWaitDialog->onFrame(frameDuration); - - mHud->onFrame(frameDuration); - - mTrainingWindow->onFrame (frameDuration); - mTradeWindow->onFrame(frameDuration); - - mTrainingWindow->checkReferenceAvailable(); - mDialogueWindow->checkReferenceAvailable(); - mTradeWindow->checkReferenceAvailable(); - mSpellBuyingWindow->checkReferenceAvailable(); - mSpellCreationDialog->checkReferenceAvailable(); - mEnchantingDialog->checkReferenceAvailable(); - mContainerWindow->checkReferenceAvailable(); - mCompanionWindow->checkReferenceAvailable(); - mConsole->checkReferenceAvailable(); -} - -void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) -{ - if (cell->mCell->isExterior()) - { - std::string name; - if (cell->mCell->mName != "") + // If in game mode, show only the pinned windows + if (gameMode) { - name = cell->mCell->mName; - mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + return; } + + GuiMode mode = mGuiModes.back(); + + switch(mode) { + case GM_QuickKeysMenu: + mQuickKeysMenu->setVisible (true); + break; + case GM_MainMenu: + mMenu->setVisible(true); + break; + case GM_Settings: + mSettingsWindow->setVisible(true); + break; + case GM_Console: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + mConsole->enable(); + break; + case GM_Scroll: + mScrollWindow->setVisible(true); + break; + case GM_Book: + mBookWindow->setVisible(true); + break; + case GM_Alchemy: + mAlchemyWindow->setVisible(true); + break; + case GM_Rest: + mWaitDialog->setVisible(true); + break; + case GM_RestBed: + mWaitDialog->setVisible(true); + mWaitDialog->bedActivated(); + break; + case GM_Levelup: + mLevelupDialog->setVisible(true); + break; + case GM_Name: + case GM_Race: + case GM_Class: + case GM_ClassPick: + case GM_ClassCreate: + case GM_Birth: + case GM_ClassGenerate: + case GM_Review: + mCharGen->spawnDialog(mode); + break; + case GM_Inventory: + { + // First, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed; + + // Show the windows we want + mMap ->setVisible(eff & GW_Map); + mStatsWindow ->setVisible(eff & GW_Stats); + mInventoryWindow->setVisible(eff & GW_Inventory); + mSpellWindow ->setVisible(eff & GW_Magic); + break; + } + case GM_Container: + mContainerWindow->setVisible(true); + mInventoryWindow->setVisible(true); + break; + case GM_Companion: + mCompanionWindow->setVisible(true); + mInventoryWindow->setVisible(true); + break; + case GM_Dialogue: + mDialogueWindow->setVisible(true); + break; + case GM_Barter: + mInventoryWindow->setVisible(true); + mTradeWindow->setVisible(true); + break; + case GM_SpellBuying: + mSpellBuyingWindow->setVisible(true); + break; + case GM_Travel: + mTravelWindow->setVisible(true); + break; + case GM_SpellCreation: + mSpellCreationDialog->setVisible(true); + break; + case GM_Enchanting: + mEnchantingDialog->setVisible(true); + break; + case GM_Training: + mTrainingWindow->setVisible(true); + break; + case GM_MerchantRepair: + mMerchantRepair->setVisible(true); + break; + case GM_Repair: + mRepair->setVisible(true); + break; + case GM_Journal: + mJournal->setVisible(true); + break; + case GM_LoadingWallpaper: + mHud->setVisible(false); + mCursor->setVisible(false); + break; + case GM_Loading: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + mCursor->setVisible(false); + break; + case GM_Video: + mCursor->setVisible(false); + mHud->setVisible(false); + break; + default: + // Unsupported mode, switch back to game + break; + } + } + + void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) + { + mStatsWindow->setValue (id, value); + mCharGen->setValue(id, value); + + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8" + }; + static ESM::Attribute::AttributeID attributes[] = + { + ESM::Attribute::Strength, + ESM::Attribute::Intelligence, + ESM::Attribute::Willpower, + ESM::Attribute::Agility, + ESM::Attribute::Speed, + ESM::Attribute::Endurance, + ESM::Attribute::Personality, + ESM::Attribute::Luck + }; + for (size_t i = 0; i < sizeof(ids)/sizeof(ids[0]); ++i) + { + if (id != ids[i]) + continue; + mPlayerAttributes[attributes[i]] = value; + break; + } + } + + + void WindowManager::setValue (int parSkill, const MWMechanics::Stat& value) + { + /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we + /// allow custom skills. + mStatsWindow->setValue(static_cast (parSkill), value); + mCharGen->setValue(static_cast (parSkill), value); + mPlayerSkillValues[parSkill] = value; + } + + void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) + { + mStatsWindow->setValue (id, value); + mHud->setValue (id, value); + mCharGen->setValue(id, value); + if (id == "HBar") + { + mPlayerHealth = value; + mCharGen->setPlayerHealth (value); + } + else if (id == "MBar") + { + mPlayerMagicka = value; + mCharGen->setPlayerMagicka (value); + } + else if (id == "FBar") + { + mPlayerFatigue = value; + mCharGen->setPlayerFatigue (value); + } + } + + #if 0 + MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) + { + if(id == "HBar") + return layerHealth; + else if (id == "MBar") + return mPlayerMagicka; + else if (id == "FBar") + return mPlayerFatigue; + } + #endif + + void WindowManager::setValue (const std::string& id, const std::string& value) + { + mStatsWindow->setValue (id, value); + if (id=="name") + mPlayerName = value; + else if (id=="race") + mPlayerRaceId = value; + } + + void WindowManager::setValue (const std::string& id, int value) + { + mStatsWindow->setValue (id, value); + } + + void WindowManager::setPlayerClass (const ESM::Class &class_) + { + mStatsWindow->setValue("class", class_.mName); + } + + void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) + { + mStatsWindow->configureSkills (major, minor); + mCharGen->configureSkills(major, minor); + mPlayerMajorSkills = major; + mPlayerMinorSkills = minor; + } + + void WindowManager::setReputation (int reputation) + { + mStatsWindow->setReputation (reputation); + } + + void WindowManager::setBounty (int bounty) + { + mStatsWindow->setBounty (bounty); + } + + void WindowManager::updateSkillArea() + { + mStatsWindow->updateSkillArea(); + } + + void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) + { + if (!dialog) + return; + dialog->setVisible(false); + mGarbageDialogs.push_back(dialog); + } + + void WindowManager::messageBox (const std::string& message, const std::vector& buttons) + { + if(buttons.empty()){ + /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ + if(!mGuiModes.empty() && mGuiModes.back() == GM_Dialogue) + mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); + else + mMessageBoxManager->createMessageBox(message); + } + else { - const ESM::Region* region = - MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); - if (region) - name = region->mName; - else - name = getGameSettingString("sDefaultCellname", "Wilderness"); + mMessageBoxManager->createInteractiveMessageBox(message, buttons); + MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); } - - mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY()); - - mMap->setCellName( name ); - mHud->setCellName( name ); - - mMap->setCellPrefix("Cell"); - mHud->setCellPrefix("Cell"); - mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); - mHud->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); } - else + + void WindowManager::enterPressed () { - mMap->setCellName( cell->mCell->mName ); - mHud->setCellName( cell->mCell->mName ); - mMap->setCellPrefix( cell->mCell->mName ); - mHud->setCellPrefix( cell->mCell->mName ); + mMessageBoxManager->enterPressed(); } -} - -void WindowManager::setInteriorMapTexture(const int x, const int y) -{ - mMap->setActiveCell(x,y, true); - mHud->setActiveCell(x,y, true); -} - -void WindowManager::setPlayerPos(const float x, const float y) -{ - mMap->setPlayerPos(x,y); - mHud->setPlayerPos(x,y); -} - -void WindowManager::setPlayerDir(const float x, const float y) -{ - mMap->setPlayerDir(x,y); - mHud->setPlayerDir(x,y); -} - -void WindowManager::setHMSVisibility(bool visible) -{ - mHud->setHmsVisible (visible); -} - -void WindowManager::setMinimapVisibility(bool visible) -{ - mHud->setMinimapVisible (visible); -} - -void WindowManager::toggleFogOfWar() -{ - mMap->toggleFogOfWar(); - mHud->toggleFogOfWar(); -} - -void WindowManager::setFocusObject(const MWWorld::Ptr& focus) -{ - mToolTips->setFocusObject(focus); -} - -void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) -{ - mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y); -} - -void WindowManager::toggleFullHelp() -{ - mToolTips->toggleFullHelp(); -} - -bool WindowManager::getFullHelp() const -{ - return mToolTips->getFullHelp(); -} - -void WindowManager::setWeaponVisibility(bool visible) -{ - mHud->setWeapVisible (visible); -} - -void WindowManager::setSpellVisibility(bool visible) -{ - mHud->setSpellVisible (visible); - mHud->setEffectVisible (visible); -} - -void WindowManager::setMouseVisible(bool visible) -{ - mCursor->setVisible(visible); -} - -void WindowManager::setDragDrop(bool dragDrop) -{ - mToolTips->setEnabled(!dragDrop); - MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); -} - -void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) -{ - std::string tag(_tag); - - std::string tokenToFind = "sCell="; - size_t tokenLength = tokenToFind.length(); - - if (tag.substr(0, tokenLength) == tokenToFind) + int WindowManager::readPressedButton () { - _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); + return mMessageBoxManager->readPressedButton(); } - else + + std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) { const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().find(tag); + MWBase::Environment::get().getWorld()->getStore().get().search(id); if (setting && setting->mValue.getType()==ESM::VT_String) - _result = setting->mValue.getString(); - else - _result = tag; + return setting->mValue.getString(); + + return default_; } -} -void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) -{ - mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); - mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); - - bool changeRes = false; - bool windowRecreated = false; - for (Settings::CategorySettingVector::const_iterator it = changed.begin(); - it != changed.end(); ++it) + void WindowManager::onDialogueWindowBye() { - if (it->first == "Video" && ( - it->second == "resolution x" - || it->second == "resolution y")) + if (mDialogueWindow) { - changeRes = true; + //FIXME set some state and stuff? + //removeDialog(dialogueWindow); + mDialogueWindow->setVisible(false); } - else if (it->first == "Video" && it->second == "vsync") - windowRecreated = true; - else if (it->first == "HUD" && it->second == "crosshair") - mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); - else if (it->first == "GUI" && it->second == "subtitles") - mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); + removeGuiMode(GM_Dialogue); } - if (changeRes) + void WindowManager::onFrame (float frameDuration) { - int x = Settings::Manager::getInt("resolution x", "Video"); - int y = Settings::Manager::getInt("resolution y", "Video"); - mHud->onResChange(x, y); - mConsole->onResChange(x, y); - mMenu->onResChange(x, y); - mSettingsWindow->center(); - mAlchemyWindow->center(); - mScrollWindow->center(); - mBookWindow->center(); - mQuickKeysMenu->center(); - mSpellBuyingWindow->center(); - mLoadingScreen->onResChange (x,y); - mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); - mInputBlocker->setSize(MyGUI::IntSize(x,y)); - } - if (windowRecreated) - { - mGuiManager->updateWindow (mRendering->getWindow ()); - mLoadingScreen->updateWindow (mRendering->getWindow ()); - } -} + mMessageBoxManager->onFrame(frameDuration); -void WindowManager::pushGuiMode(GuiMode mode) -{ - if (mode==GM_Inventory && mAllowed==GW_None) - return; + mToolTips->onFrame(frameDuration); + if (mDragAndDrop->mIsOnDragAndDrop) + { + assert(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + } - // If this mode already exists somewhere in the stack, just bring it to the front. - if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) - { - mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + mDialogueWindow->onFrame(); + + mInventoryWindow->onFrame(); + + mStatsWindow->onFrame(); + + mWaitDialog->onFrame(frameDuration); + + mHud->onFrame(frameDuration); + + mTrainingWindow->onFrame (frameDuration); + mTradeWindow->onFrame(frameDuration); + + mTrainingWindow->checkReferenceAvailable(); + mDialogueWindow->checkReferenceAvailable(); + mTradeWindow->checkReferenceAvailable(); + mSpellBuyingWindow->checkReferenceAvailable(); + mSpellCreationDialog->checkReferenceAvailable(); + mEnchantingDialog->checkReferenceAvailable(); + mContainerWindow->checkReferenceAvailable(); + mCompanionWindow->checkReferenceAvailable(); + mConsole->checkReferenceAvailable(); } - mGuiModes.push_back(mode); - - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::popGuiMode() -{ - if (!mGuiModes.empty()) - mGuiModes.pop_back(); - - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::removeGuiMode(GuiMode mode) -{ - std::vector::iterator it = mGuiModes.begin(); - while (it != mGuiModes.end()) + void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) { - if (*it == mode) - it = mGuiModes.erase(it); + if (cell->mCell->isExterior()) + { + std::string name; + if (cell->mCell->mName != "") + { + name = cell->mCell->mName; + mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); + } + else + { + const ESM::Region* region = + MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); + if (region) + name = region->mName; + else + name = getGameSettingString("sDefaultCellname", "Wilderness"); + } + + mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY()); + + mMap->setCellName( name ); + mHud->setCellName( name ); + + mMap->setCellPrefix("Cell"); + mHud->setCellPrefix("Cell"); + mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); + mHud->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); + } else - ++it; + { + mMap->setCellName( cell->mCell->mName ); + mHud->setCellName( cell->mCell->mName ); + mMap->setCellPrefix( cell->mCell->mName ); + mHud->setCellPrefix( cell->mCell->mName ); + } + } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) -{ - mHud->setSelectedSpell(spellId, successChancePercent); - - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - mSpellWindow->setTitle(spell->mName); -} - -void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) -{ - const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() - .find(MWWorld::Class::get(item).getEnchantment(item)); - - int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; - mHud->setSelectedEnchantItem(item, chargePercent); - mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); -} - -void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) -{ - int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; - mHud->setSelectedWeapon(item, durabilityPercent); - mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); -} - -void WindowManager::unsetSelectedSpell() -{ - mHud->unsetSelectedSpell(); - mSpellWindow->setTitle("#{sNone}"); -} - -void WindowManager::unsetSelectedWeapon() -{ - mHud->unsetSelectedWeapon(); - mInventoryWindow->setTitle("#{sSkillHandtohand}"); -} - -void WindowManager::getMousePosition(int &x, int &y) -{ - const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); - x = pos.left; - y = pos.top; -} - -void WindowManager::getMousePosition(float &x, float &y) -{ - const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); - x = pos.left; - y = pos.top; - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - x /= viewSize.width; - y /= viewSize.height; -} - -bool WindowManager::getWorldMouseOver() -{ - return mHud->getWorldMouseOver(); -} - -void WindowManager::executeInConsole (const std::string& path) -{ - mConsole->executeFile (path); -} - -void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) -{ - mFPS = fps; - mTriangleCount = triangleCount; - mBatchCount = batchCount; -} - -MyGUI::Gui* WindowManager::getGui() const { return mGui; } - -MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } -MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } -MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } -MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } -MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } -MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } -MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } -MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } -MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } -MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } -MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } -MWGui::Console* WindowManager::getConsole() { return mConsole; } - -bool WindowManager::isAllowed (GuiWindow wnd) const -{ - return mAllowed & wnd; -} - -void WindowManager::allow (GuiWindow wnd) -{ - mAllowed = (GuiWindow)(mAllowed | wnd); - - if (wnd & GW_Inventory) + void WindowManager::setInteriorMapTexture(const int x, const int y) { - mBookWindow->setInventoryAllowed (true); - mScrollWindow->setInventoryAllowed (true); + mMap->setActiveCell(x,y, true); + mHud->setActiveCell(x,y, true); + } + + void WindowManager::setPlayerPos(const float x, const float y) + { + mMap->setPlayerPos(x,y); + mHud->setPlayerPos(x,y); + } + + void WindowManager::setPlayerDir(const float x, const float y) + { + mMap->setPlayerDir(x,y); + mHud->setPlayerDir(x,y); + } + + void WindowManager::setHMSVisibility(bool visible) + { + mHud->setHmsVisible (visible); + } + + void WindowManager::setMinimapVisibility(bool visible) + { + mHud->setMinimapVisible (visible); + } + + void WindowManager::toggleFogOfWar() + { + mMap->toggleFogOfWar(); + mHud->toggleFogOfWar(); + } + + void WindowManager::setFocusObject(const MWWorld::Ptr& focus) + { + mToolTips->setFocusObject(focus); + } + + void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) + { + mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y); + } + + void WindowManager::toggleFullHelp() + { + mToolTips->toggleFullHelp(); + } + + bool WindowManager::getFullHelp() const + { + return mToolTips->getFullHelp(); + } + + void WindowManager::setWeaponVisibility(bool visible) + { + mHud->setWeapVisible (visible); + } + + void WindowManager::setSpellVisibility(bool visible) + { + mHud->setSpellVisible (visible); + mHud->setEffectVisible (visible); + } + + void WindowManager::setMouseVisible(bool visible) + { + mCursor->setVisible(visible); + } + + void WindowManager::setDragDrop(bool dragDrop) + { + mToolTips->setEnabled(!dragDrop); + MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); + } + + void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) + { + std::string tag(_tag); + + std::string tokenToFind = "sCell="; + size_t tokenLength = tokenToFind.length(); + + if (tag.substr(0, tokenLength) == tokenToFind) + { + _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); + } + else + { + const ESM::GameSetting *setting = + MWBase::Environment::get().getWorld()->getStore().get().find(tag); + + if (setting && setting->mValue.getType()==ESM::VT_String) + _result = setting->mValue.getString(); + else + _result = tag; + } + } + + void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) + { + mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); + mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); + + bool changeRes = false; + bool windowRecreated = 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; + } + else if (it->first == "Video" && it->second == "vsync") + windowRecreated = true; + else if (it->first == "HUD" && it->second == "crosshair") + mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); + else if (it->first == "GUI" && it->second == "subtitles") + mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); + } + + if (changeRes) + { + int x = Settings::Manager::getInt("resolution x", "Video"); + int y = Settings::Manager::getInt("resolution y", "Video"); + mHud->onResChange(x, y); + mConsole->onResChange(x, y); + mMenu->onResChange(x, y); + mSettingsWindow->center(); + mAlchemyWindow->center(); + mScrollWindow->center(); + mBookWindow->center(); + mQuickKeysMenu->center(); + mSpellBuyingWindow->center(); + mLoadingScreen->onResChange (x,y); + mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); + mInputBlocker->setSize(MyGUI::IntSize(x,y)); + } + if (windowRecreated) + { + mGuiManager->updateWindow (mRendering->getWindow ()); + mLoadingScreen->updateWindow (mRendering->getWindow ()); + } + } + + void WindowManager::pushGuiMode(GuiMode mode) + { + if (mode==GM_Inventory && mAllowed==GW_None) + return; + + + // If this mode already exists somewhere in the stack, just bring it to the front. + if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + { + mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + } + + mGuiModes.push_back(mode); + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); + } + + void WindowManager::popGuiMode() + { + if (!mGuiModes.empty()) + mGuiModes.pop_back(); + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); + } + + void WindowManager::removeGuiMode(GuiMode mode) + { + std::vector::iterator it = mGuiModes.begin(); + while (it != mGuiModes.end()) + { + if (*it == mode) + it = mGuiModes.erase(it); + else + ++it; + } + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); + } + + void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) + { + mHud->setSelectedSpell(spellId, successChancePercent); + + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + mSpellWindow->setTitle(spell->mName); + } + + void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() + .find(MWWorld::Class::get(item).getEnchantment(item)); + + int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; + mHud->setSelectedEnchantItem(item, chargePercent); + mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); + } + + void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) + { + int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; + mHud->setSelectedWeapon(item, durabilityPercent); + mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); + } + + void WindowManager::unsetSelectedSpell() + { + mHud->unsetSelectedSpell(); + mSpellWindow->setTitle("#{sNone}"); + } + + void WindowManager::unsetSelectedWeapon() + { + mHud->unsetSelectedWeapon(); + mInventoryWindow->setTitle("#{sSkillHandtohand}"); + } + + void WindowManager::getMousePosition(int &x, int &y) + { + const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); + x = pos.left; + y = pos.top; + } + + void WindowManager::getMousePosition(float &x, float &y) + { + const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition(); + x = pos.left; + y = pos.top; + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + x /= viewSize.width; + y /= viewSize.height; + } + + bool WindowManager::getWorldMouseOver() + { + return mHud->getWorldMouseOver(); + } + + void WindowManager::executeInConsole (const std::string& path) + { + mConsole->executeFile (path); + } + + void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) + { + mFPS = fps; + mTriangleCount = triangleCount; + mBatchCount = batchCount; + } + + MyGUI::Gui* WindowManager::getGui() const { return mGui; } + + MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } + MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } + MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } + MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } + MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } + MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } + MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } + MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } + MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } + MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } + MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } + MWGui::Console* WindowManager::getConsole() { return mConsole; } + + bool WindowManager::isAllowed (GuiWindow wnd) const + { + return mAllowed & wnd; + } + + void WindowManager::allow (GuiWindow wnd) + { + mAllowed = (GuiWindow)(mAllowed | wnd); + + if (wnd & GW_Inventory) + { + mBookWindow->setInventoryAllowed (true); + mScrollWindow->setInventoryAllowed (true); + } + + updateVisible(); + } + + void WindowManager::disallowAll() + { + mAllowed = GW_None; + + mBookWindow->setInventoryAllowed (false); + mScrollWindow->setInventoryAllowed (false); + + updateVisible(); + } + + void WindowManager::toggleVisible (GuiWindow wnd) + { + mShown = (mShown & wnd) ? (GuiWindow) (mShown & ~wnd) : (GuiWindow) (mShown | wnd); + updateVisible(); + } + + bool WindowManager::isGuiMode() const + { + return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); + } + + bool WindowManager::isConsoleMode() const + { + if (!mGuiModes.empty() && mGuiModes.back()==GM_Console) + return true; + return false; + } + + MWGui::GuiMode WindowManager::getMode() const + { + if (mGuiModes.empty()) + return GM_None; + return mGuiModes.back(); + } + + std::map > WindowManager::getPlayerSkillValues() + { + return mPlayerSkillValues; + } + + std::map > WindowManager::getPlayerAttributeValues() + { + return mPlayerAttributes; + } + + WindowManager::SkillList WindowManager::getPlayerMinorSkills() + { + return mPlayerMinorSkills; + } + + WindowManager::SkillList WindowManager::getPlayerMajorSkills() + { + return mPlayerMajorSkills; + } + + void WindowManager::disallowMouse() + { + mInputBlocker->setVisible (true); + } + + void WindowManager::allowMouse() + { + mInputBlocker->setVisible (!isGuiMode ()); + } + + void WindowManager::notifyInputActionBound () + { + mSettingsWindow->updateControlsBox (); + allowMouse(); + } + + void WindowManager::showCrosshair (bool show) + { + mHud->setCrosshairVisible (show && mCrosshairEnabled); + } + + void WindowManager::activateQuickKey (int index) + { + mQuickKeysMenu->activateQuickKey(index); + } + + bool WindowManager::getSubtitlesEnabled () + { + return mSubtitlesEnabled; + } + + void WindowManager::toggleHud () + { + mHudEnabled = !mHudEnabled; + mHud->setVisible (mHudEnabled); + } + + void WindowManager::setLoadingProgress (const std::string& stage, int depth, int current, int total) + { + mLoadingScreen->setLoadingProgress (stage, depth, current, total); + } + + void WindowManager::loadingDone () + { + mLoadingScreen->loadingDone (); + } + + bool WindowManager::getPlayerSleeping () + { + return mWaitDialog->getSleeping(); + } + + void WindowManager::wakeUpPlayer() + { + mWaitDialog->wakeUp(); + } + + void WindowManager::addVisitedLocation(const std::string& name, int x, int y) + { + mMap->addVisitedLocation (name, x, y); + } + + void WindowManager::startSpellMaking(MWWorld::Ptr actor) + { + mSpellCreationDialog->startSpellMaking (actor); + } + + void WindowManager::startEnchanting (MWWorld::Ptr actor) + { + mEnchantingDialog->startEnchanting (actor); + } + + void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) + { + mEnchantingDialog->startSelfEnchanting(soulgem); + } + + void WindowManager::startTraining(MWWorld::Ptr actor) + { + mTrainingWindow->startTraining(actor); + } + + void WindowManager::startRepair(MWWorld::Ptr actor) + { + mMerchantRepair->startRepair(actor); + } + + void WindowManager::startRepairItem(MWWorld::Ptr item) + { + mRepair->startRepairItem(item); + } + + const Translation::Storage& WindowManager::getTranslationDataStorage() const + { + return mTranslationDataStorage; + } + + void WindowManager::showCompanionWindow(MWWorld::Ptr actor) + { + mCompanionWindow->open(actor); + } + + void WindowManager::changePointer(const std::string &name) + { + mCursor->onCursorChange(name); + } + + void WindowManager::showSoulgemDialog(MWWorld::Ptr item) + { + mSoulgemDialog->show(item); + } + + void WindowManager::frameStarted (float dt) + { + mInventoryWindow->doRenderUpdate (); } - updateVisible(); -} - -void WindowManager::disallowAll() -{ - mAllowed = GW_None; - - mBookWindow->setInventoryAllowed (false); - mScrollWindow->setInventoryAllowed (false); - - updateVisible(); -} - -void WindowManager::toggleVisible (GuiWindow wnd) -{ - mShown = (mShown & wnd) ? (GuiWindow) (mShown & ~wnd) : (GuiWindow) (mShown | wnd); - updateVisible(); -} - -bool WindowManager::isGuiMode() const -{ - return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); -} - -bool WindowManager::isConsoleMode() const -{ - if (!mGuiModes.empty() && mGuiModes.back()==GM_Console) - return true; - return false; -} - -MWGui::GuiMode WindowManager::getMode() const -{ - if (mGuiModes.empty()) - return GM_None; - return mGuiModes.back(); -} - -std::map > WindowManager::getPlayerSkillValues() -{ - return mPlayerSkillValues; -} - -std::map > WindowManager::getPlayerAttributeValues() -{ - return mPlayerAttributes; -} - -WindowManager::SkillList WindowManager::getPlayerMinorSkills() -{ - return mPlayerMinorSkills; -} - -WindowManager::SkillList WindowManager::getPlayerMajorSkills() -{ - return mPlayerMajorSkills; -} - -void WindowManager::disallowMouse() -{ - mInputBlocker->setVisible (true); -} - -void WindowManager::allowMouse() -{ - mInputBlocker->setVisible (!isGuiMode ()); -} - -void WindowManager::notifyInputActionBound () -{ - mSettingsWindow->updateControlsBox (); - allowMouse(); -} - -void WindowManager::showCrosshair (bool show) -{ - mHud->setCrosshairVisible (show && mCrosshairEnabled); -} - -void WindowManager::activateQuickKey (int index) -{ - mQuickKeysMenu->activateQuickKey(index); -} - -bool WindowManager::getSubtitlesEnabled () -{ - return mSubtitlesEnabled; -} - -void WindowManager::toggleHud () -{ - mHudEnabled = !mHudEnabled; - mHud->setVisible (mHudEnabled); -} - -void WindowManager::setLoadingProgress (const std::string& stage, int depth, int current, int total) -{ - mLoadingScreen->setLoadingProgress (stage, depth, current, total); -} - -void WindowManager::loadingDone () -{ - mLoadingScreen->loadingDone (); -} - -bool WindowManager::getPlayerSleeping () -{ - return mWaitDialog->getSleeping(); -} - -void WindowManager::wakeUpPlayer() -{ - mWaitDialog->wakeUp(); -} - -void WindowManager::addVisitedLocation(const std::string& name, int x, int y) -{ - mMap->addVisitedLocation (name, x, y); -} - -void WindowManager::startSpellMaking(MWWorld::Ptr actor) -{ - mSpellCreationDialog->startSpellMaking (actor); -} - -void WindowManager::startEnchanting (MWWorld::Ptr actor) -{ - mEnchantingDialog->startEnchanting (actor); -} - -void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) -{ - mEnchantingDialog->startSelfEnchanting(soulgem); -} - -void WindowManager::startTraining(MWWorld::Ptr actor) -{ - mTrainingWindow->startTraining(actor); -} - -void WindowManager::startRepair(MWWorld::Ptr actor) -{ - mMerchantRepair->startRepair(actor); -} - -void WindowManager::startRepairItem(MWWorld::Ptr item) -{ - mRepair->startRepairItem(item); -} - -const Translation::Storage& WindowManager::getTranslationDataStorage() const -{ - return mTranslationDataStorage; -} - -void WindowManager::showCompanionWindow(MWWorld::Ptr actor) -{ - mCompanionWindow->open(actor); -} - -void WindowManager::changePointer(const std::string &name) -{ - mCursor->onCursorChange(name); -} - -void WindowManager::showSoulgemDialog(MWWorld::Ptr item) -{ - mSoulgemDialog->show(item); -} - -void WindowManager::frameStarted (float dt) -{ - mInventoryWindow->doRenderUpdate (); } diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 53ba1b9fd..e5a94fc72 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -2,25 +2,26 @@ #include "exposedwindow.hpp" -using namespace MWGui; - -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) - : WindowBase(parLayout), mPinned(false), mVisible(false) +namespace MWGui { - ExposedWindow* window = static_cast(mMainWidget); - mPinButton = window->getSkinWidget ("Button"); + WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) + : WindowBase(parLayout), mPinned(false), mVisible(false) + { + ExposedWindow* window = static_cast(mMainWidget); + mPinButton = window->getSkinWidget ("Button"); - mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); -} - -void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) -{ - mPinned = !mPinned; - - if (mPinned) - mPinButton->changeWidgetSkin ("PinDown"); - else - mPinButton->changeWidgetSkin ("PinUp"); - - onPinToggled(); + mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); + } + + void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) + { + mPinned = !mPinned; + + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); + + onPinToggled(); + } } From 3c5e4ceefd87140156bfa87c314242baef30676e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 16:46:32 +0200 Subject: [PATCH 307/817] Workaround for ambiguous "Chargen_plank" ID in chargen script (one at -22,16 and one at -2,-9) --- apps/openmw/mwworld/store.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index f69f606b4..fb3f8c482 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -415,8 +415,18 @@ namespace MWWorld } }; - typedef std::map DynamicInt; - typedef std::map, ESM::Cell> DynamicExt; + struct DynamicExtCmp + { + bool operator()(const std::pair &left, const std::pair &right) const { + if (left.first == right.first) { + return left.second < right.second; + } + return left.first < right.first; + } + }; + + typedef std::map DynamicInt; + typedef std::map, ESM::Cell, DynamicExtCmp> DynamicExt; DynamicInt mInt; DynamicExt mExt; From b34caccd2ec90a582e4732d29fb1fc7a10a86e92 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 16:46:38 +0200 Subject: [PATCH 308/817] Fix moving NPCs not getting their collision box moved --- libs/openengine/bullet/physic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 524f57c1c..eaeae7dc3 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -511,8 +511,8 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { - // This isn't needed as there are no dynamic objects at this point - //dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + // This seems to be needed for character controller objects + dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); if(isDebugCreated) { mDebugDrawer->step(); From c753eb4c287729759e897ef35fdd6b36b3acf429 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 18 Apr 2013 18:35:01 +0100 Subject: [PATCH 309/817] another way to do pathfinding. Slightly less powerfull algorithme in theory, but morrowind pathgrids are so simple it shouldn't be a problem. Hope it solves the bug for KittyCat --- apps/openmw/mwmechanics/pathfinding.cpp | 35 ++++++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 7c22e5470..2f27d25f8 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -1,5 +1,5 @@ #include "pathfinding.hpp" -#include +#include #include #include "boost/tuple/tuple.hpp" #include "OgreMath.h" @@ -55,7 +55,7 @@ namespace struct found_path {}; - class goalVisited : public boost::default_astar_visitor + /*class goalVisited : public boost::default_astar_visitor { public: goalVisited(PointID goal) : mGoal(goal) {} @@ -69,7 +69,7 @@ namespace PointID mGoal; }; - class DistanceHeuristic : public boost::astar_heuristic + class DistanceHeuristic : public boost::atasr_heuristic { public: DistanceHeuristic(const PathGridGraph & l, PointID goal) @@ -87,11 +87,23 @@ namespace private: const PathGridGraph & mGraph; PointID mGoal; - }; -} + };*/ + + class goalVisited : public boost::default_dijkstra_visitor + { + public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } + private: + PointID mGoal; + }; + -namespace MWMechanics -{ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; @@ -126,13 +138,12 @@ namespace MWMechanics std::list shortest_path; try { - boost::astar_search + boost::dijkstra_shortest_paths ( graph, start, - DistanceHeuristic(graph,end), boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); + ); } catch(found_path fg) { for(PointID v = end;; v = p[v]) { @@ -146,6 +157,10 @@ namespace MWMechanics //end of helpers functions +} + +namespace MWMechanics +{ PathFinder::PathFinder() { mIsPathConstructed = false; From f9deb593d1f5d6baba89b57cc8f5f3ba544917a6 Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 18 Apr 2013 21:37:58 +0200 Subject: [PATCH 310/817] Bugfix #578 --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d34c4b97f..66d20e662 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -548,7 +548,7 @@ namespace MWMechanics float bribeMod; if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->getFloat(); - if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); + else if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); else bribeMod = gmst.find("fBribe1000Mod")->getFloat(); float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; From 3b3a052f4f7592b756583a0bc7fdadfe04b5a920 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Apr 2013 22:36:48 +0200 Subject: [PATCH 311/817] increased version number --- CMakeLists.txt | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6a101790..9f12b11fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 22) +set (OPENMW_VERSION_MINOR 23) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") diff --git a/readme.txt b/readme.txt index 8edb0c4b3..9bce063fa 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.22.0 +Version: 0.23.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From 257f9403660e82f3fed9231c6784429b13fdea38 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Apr 2013 22:50:04 +0200 Subject: [PATCH 312/817] updated changelog --- readme.txt | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/readme.txt b/readme.txt index 9bce063fa..5f3845776 100644 --- a/readme.txt +++ b/readme.txt @@ -94,6 +94,65 @@ Allowed options: CHANGELOG +0.23.0 + +Bug #522: Player collides with placeable items +Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open +Bug #561: Tooltip word wrapping delay +Bug #578: Bribing works incorrectly +Bug #601: PositionCell fails on negative coordinates +Bug #606: Some NPCs hairs not rendered with Better Heads addon +Bug #609: Bad rendering of bone boots +Bug #613: Messagebox causing assert to fail +Bug #631: Segfault on shutdown +Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard +Bug #635: Scale NPCs depending on race +Bug #643: Dialogue Race select function is inverted +Bug #646: Twohanded weapons don't work properly +Bug #654: Crash when dropping objects without a collision shape +Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell +Bug #660: "g" in "change" cut off in Race Menu +Bug #661: Arrille sells me the key to his upstairs room +Bug #662: Day counter starts at 2 instead of 1 +Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur +Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window. +Bug #666: Looking up/down problem +Bug #667: Active effects border visible during loading +Bug #669: incorrect player position at new game start +Bug #670: race selection menu: sex, face and hair left button not totally clickable +Bug #671: new game: player is naked +Bug #674: buying or selling items doesn't change amount of gold +Bug #675: fatigue is not set to its maximum when starting a new game +Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly +Bug #680: different gold coins in Tel Mara +Bug #682: Race menu ignores playable flag for some hairs and faces +Bug #685: Script compiler does not accept ":" after a function name +Bug #688: dispose corpse makes cross-hair to disappear +Bug #691: Auto equipping ignores equipment conditions +Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder +Bug #696: Draugr incorrect head offset +Bug #697: Sail transparency issue +Bug #700: "On the rocks" mod does not load its UV coordinates correctly. +Bug #702: Some race mods don't work +Bug #711: Crash during character creation +Bug #715: Growing Tauryon +Feature #55/657: Item Repairing +Feature #62/87: Enchanting +Feature #99: Pathfinding +Feature #104: AI Package: Travel +Feature #129: Levelled items +Feature #204: Texture animations +Feature #239: Fallback-Settings +Feature #535: Console object selection improvements +Feature #629: Add levelup description in levelup layout dialog +Feature #630: Optional format subrecord in (tes3) header +Feature #641: Armor rating +Feature #645: OnDeath script function +Feature #683: Companion item UI +Feature #698: Basic Particles +Task #648: Split up components/esm/loadlocks +Task #695: mwgui cleanup + 0.22.0 Bug #311: Potential infinite recursion in script compiler From ef9afeb53e5b48fd3a903a1e26a8a869ef89e7ee Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 23:51:43 +0200 Subject: [PATCH 313/817] Auto calculate attributes if there are not specified in the NPC record --- apps/openmw/mwclass/npc.cpp | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7cda87bb1..ea49ae4a4 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,67 @@ namespace { return new CustomData (*this); } + + void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) + { + // race bonus + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mRace); + + bool male = (npc->mFlags & ESM::NPC::Female) == 0; + + int level = creatureStats.getLevel(); + + for (int i=0; imData.mAttributeValues[i]; + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); + } + + // class bonus + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mClass); + + for (int i=0; i<2; ++i) + { + int attribute = class_->mData.mAttribute[i]; + if (attribute>=0 && attribute<8) + { + creatureStats.getAttribute(attribute).setBase ( + creatureStats.getAttribute(attribute).getBase() + 10); + } + } + + // skill bonus + for (int attribute=0; attributegetStore().get().find(j); + + if (skill->mData.mAttribute != attribute) + continue; + + // is this a minor or major skill? + float add=0.2; + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][0] == j) + add=0.5; + } + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][1] == j) + add=1.0; + } + modifierSum += add; + } + creatureStats.getAttribute(attribute).setBase ( std::min(creatureStats.getAttribute(attribute).getBase() + + static_cast((level-1) * modifierSum+0.5), 100) ); + } + } } namespace MWClass @@ -126,15 +187,14 @@ namespace MWClass } else { - for (int i=0; i<8; ++i) - data->mCreatureStats.getAttribute (i).set (10); - for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + + autoCalculateAttributes(ref->mBase, data->mCreatureStats); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 92e06cebf3f6cbd0930529ab026221c5ff2c69ca Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 00:26:36 +0200 Subject: [PATCH 314/817] last minute change to changelog --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 5f3845776..d5a5dcc18 100644 --- a/readme.txt +++ b/readme.txt @@ -136,6 +136,7 @@ Bug #700: "On the rocks" mod does not load its UV coordinates correctly. Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon +Bug #725: Auto calculate stats Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From e92897526c9fb6bc8fb1acf836b7b841374cc919 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 01:33:04 +0200 Subject: [PATCH 315/817] Only use the shader based mygui manager if the fixed pipeline is unavailable --- libs/openengine/gui/manager.cpp | 30 ++++++++++++++++++++++++++---- libs/openengine/gui/manager.hpp | 5 +++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index f9117586f..a0a4ab0ae 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -559,6 +559,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool assert(mgr); mSceneMgr = mgr; + mShaderRenderManager = NULL; + mRenderManager = NULL; using namespace MyGUI; @@ -574,7 +576,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new MyGUI::ShaderBasedRenderManager(); + if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) + mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); + else + mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); @@ -582,7 +587,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool if (!theLogFile.empty()) LogManager::getInstance().createDefaultSource(theLogFile); - mRenderManager->initialise(wnd, mgr); + if (mShaderRenderManager) + mShaderRenderManager->initialise(wnd, mgr); + else + mRenderManager->initialise(wnd, mgr); mDataManager->initialise("General"); // Create GUI @@ -592,8 +600,16 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) { - mRenderManager->setRenderWindow (wnd); - mRenderManager->setActiveViewport(0); + if (mShaderRenderManager) + { + mShaderRenderManager->setRenderWindow (wnd); + mShaderRenderManager->setActiveViewport(0); + } + else + { + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); + } } void MyGUIManager::shutdown() @@ -606,6 +622,12 @@ void MyGUIManager::shutdown() delete mRenderManager; mRenderManager = NULL; } + if(mShaderRenderManager) + { + mShaderRenderManager->shutdown(); + delete mShaderRenderManager; + mShaderRenderManager = NULL; + } if(mDataManager) { mDataManager->shutdown(); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index eec867ff8..9535f2a24 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,6 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; + class OgreRenderManager; class ShaderBasedRenderManager; } @@ -25,12 +26,12 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::ShaderBasedRenderManager* mRenderManager; + MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mShaderRenderManager; Ogre::SceneManager* mSceneMgr; public: - MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL), mGui(NULL) {} MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) { setup(wnd,mgr,logging, logDir); From 50bb92beb349f340801923565db15c1c78832c38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 02:01:50 -0700 Subject: [PATCH 316/817] Use a method to set the visibility flags and render queue. --- apps/openmw/mwrender/activatoranimation.cpp | 24 +------------------ apps/openmw/mwrender/animation.cpp | 26 +++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/creatureanimation.cpp | 25 +------------------- apps/openmw/mwrender/npcanimation.cpp | 21 ++++------------- 5 files changed, 35 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 1f9a2e23c..c3a3045c2 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -1,10 +1,5 @@ #include "activatoranimation.hpp" -#include -#include -#include -#include - #include "renderconst.hpp" #include "../mwbase/world.hpp" @@ -27,24 +22,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) const std::string name = "meshes\\"+ref->mBase->mModel; addObjectList(mPtr.getRefData().getBaseNode(), name, false); - const NifOgre::ObjectList &objlist = mObjectLists.back(); - for(size_t i = 0;i < objlist.mEntities.size();i++) - { - Ogre::Entity *ent = objlist.mEntities[i]; - ent->setVisibilityFlags(RV_Misc); - - for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = ent->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < objlist.mParticles.size();i++) - { - Ogre::ParticleSystem *part = objlist.mParticles[i]; - part->setVisibilityFlags(RV_Misc); - part->setRenderQueueGroup(RQG_Alpha); - } + setRenderProperties(mObjectLists.back(), RV_Misc, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 11876a247..8e5bd0108 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -150,6 +152,30 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b mCurrentControllers = &objlist.mControllers; } +void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) +{ + for(size_t i = 0;i < objlist.mEntities.size();i++) + { + Ogre::Entity *ent = objlist.mEntities[i]; + if(visflags != 0) + ent->setVisibilityFlags(visflags); + + for(unsigned int j = 0;j < ent->getNumSubEntities();++j) + { + Ogre::SubEntity* subEnt = ent->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? transqueue : solidqueue); + } + } + for(size_t i = 0;i < objlist.mParticles.size();i++) + { + Ogre::ParticleSystem *part = objlist.mParticles[i]; + if(visflags != 0) + part->setVisibilityFlags(visflags); + // TODO: Check particle material for actual transparency + part->setRenderQueueGroup(transqueue); + } +} + Ogre::Node *Animation::getNode(const std::string &name) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index f8ddceeaa..db2195c34 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -85,6 +85,8 @@ protected: void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); + static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index a48b8da9f..51632b2ee 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,10 +1,5 @@ #include "creatureanimation.hpp" -#include -#include -#include -#include - #include "renderconst.hpp" #include "../mwbase/world.hpp" @@ -30,25 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); addObjectList(mPtr.getRefData().getBaseNode(), model, false); - - const NifOgre::ObjectList &objlist = mObjectLists.back(); - for(size_t i = 0;i < objlist.mEntities.size();i++) - { - Ogre::Entity *ent = objlist.mEntities[i]; - ent->setVisibilityFlags(RV_Actors); - - for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = ent->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < objlist.mParticles.size();i++) - { - Ogre::ParticleSystem *part = objlist.mParticles[i]; - part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); - } + setRenderProperties(mObjectLists.back(), RV_Actors, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cea0225ef..0b05b4ba6 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -361,25 +361,13 @@ void NpcAnimation::updateParts(bool forceupdate) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); - for(size_t i = 0;i < objects.mEntities.size();i++) - { - objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if(mVisibilityFlags != 0) - objects.mEntities[i]->setVisibilityFlags(mVisibilityFlags); + setRenderProperties(objects, mVisibilityFlags, RQG_Main, RQG_Alpha); - for(unsigned int j=0; j < objects.mEntities[i]->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = objects.mEntities[i]->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } + for(size_t i = 0;i < objects.mEntities.size();i++) + objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); for(size_t i = 0;i < objects.mParticles.size();i++) - { objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if(mVisibilityFlags != 0) - objects.mParticles[i]->setVisibilityFlags(mVisibilityFlags); - objects.mParticles[i]->setRenderQueueGroup(RQG_Alpha); - } + if(objects.mSkelBase) { Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); @@ -395,6 +383,7 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } + return objects; } From f13b0c884fa1eb4a93060a1722f45677bf458d08 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 14:41:26 +0200 Subject: [PATCH 317/817] hotfix for CharacterPreview destructor --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8396acaea..41770d489 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -21,13 +21,15 @@ namespace MWRender CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mSizeX(sizeX) - , mSizeY(sizeY) - , mName(name) + + : mSceneMgr (0) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) + , mName(name) + , mSizeX(sizeX) + , mSizeY(sizeY) { } @@ -88,16 +90,20 @@ namespace MWRender CharacterPreview::~CharacterPreview () { - //Ogre::TextureManager::getSingleton().remove(mName); - mSceneMgr->destroyCamera (mName); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneMgr) + { + //Ogre::TextureManager::getSingleton().remove(mName); + mSceneMgr->destroyAllCameras(); + delete mAnimation; + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + } } void CharacterPreview::rebuild() { assert(mAnimation); delete mAnimation; + mAnimation = 0; mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); From a8e3acd6c4db2c502e3f1de49bb054d53ba4ca5f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 17:57:22 +0200 Subject: [PATCH 318/817] Fix consecutive dialogue choices --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 9380ab76c..220adf566 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -426,6 +426,7 @@ namespace MWDialogue void DialogueManager::questionAnswered (const std::string& answer) { + if (mChoiceMap.find(answer) != mChoiceMap.end()) { mChoice = mChoiceMap[answer]; @@ -442,6 +443,10 @@ namespace MWDialogue std::string text = info->mResponse; parseText (text); + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); @@ -449,9 +454,6 @@ namespace MWDialogue mLastDialogue = *info; } } - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; } updateTopics(); From 1051fa51a71f964fa55a73d054c558862ee95ed0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 15:07:08 -0700 Subject: [PATCH 319/817] Recognize NiFlipController --- components/nif/controller.hpp | 23 +++++++++++++++++++++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 1 + components/nif/recordptr.hpp | 1 + 4 files changed, 26 insertions(+) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index aa6a9ef4f..011e0e445 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -303,5 +303,28 @@ public: } }; +class NiFlipController : public Controller +{ +public: + int mTexSlot; + float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources + NiSourceTextureList mSources; + + void read(NIFStream *nif) + { + Controller::read(nif); + mTexSlot = nif->getUInt(); + /*unknown=*/nif->getUInt();/*0?*/ + mDelta = nif->getFloat(); + mSources.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + mSources.post(nif); + } +}; + } // Namespace #endif diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 2c4f3506e..a66bd99db 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -235,6 +235,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiMaterialColorController", &construct , RC_NiMaterialColorController }, { "NiBSPArrayController", &construct , RC_NiBSPArrayController }, { "NiParticleSystemController", &construct , RC_NiParticleSystemController }, + { "NiFlipController", &construct , RC_NiFlipController }, { "NiAmbientLight", &construct , RC_NiLight }, { "NiDirectionalLight", &construct , RC_NiLight }, { "NiTextureEffect", &construct , RC_NiTextureEffect }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 97b10503e..3f852ed83 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -60,6 +60,7 @@ enum RecordType RC_NiMaterialColorController, RC_NiBSPArrayController, RC_NiParticleSystemController, + RC_NiFlipController, RC_NiBSAnimationNode, RC_NiLight, RC_NiTextureEffect, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index c5bafea12..2ecde7f60 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -163,6 +163,7 @@ typedef RecordPtrT NiAutoNormalParticlesDataPtr; typedef RecordListT NodeList; typedef RecordListT PropertyList; +typedef RecordListT NiSourceTextureList; } // Namespace #endif From f37a71f02584dddfe50655dea4689aaea4bf89f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 23:56:47 -0700 Subject: [PATCH 320/817] Use a separate method to build node-based controllers --- components/nifogre/ogrenifloader.cpp | 77 +++++++++++++++------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index c5cc45ae9..21acfca0f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -575,6 +575,44 @@ class NIFObjectLoader } + static void createNodeControllers(const std::string &name, Nif::ControllerPtr ctrl, ObjectList &objectlist, int animflags) + { + do { + if(ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + else if(ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + } + ctrl = ctrl->next; + } while(!ctrl.empty()); + } + + static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags, int animflags, int partflags) @@ -613,6 +651,9 @@ class NIFObjectLoader e = e->extra; } + if(!node->controller.empty()) + createNodeControllers(name, node->controller, objectlist, animflags); + if(node->recType == Nif::RC_NiCamera) { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); @@ -620,42 +661,6 @@ class NIFObjectLoader objectlist.mCameras.push_back(trgtbone); } - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if(ctrl->recType == Nif::RC_NiKeyframeController) - { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - } - ctrl = ctrl->next; - } - if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { createEntity(name, group, sceneMgr, objectlist, node, flags, animflags); From ace7d647e5af1182a972505bb6f3aa1a01ee16d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Apr 2013 15:35:19 -0700 Subject: [PATCH 321/817] Add a method to apply a NodeTargetValue-based controller to a specified node. --- components/nifogre/ogrenifloader.cpp | 147 +++++++++++++++------------ components/nifogre/ogrenifloader.hpp | 2 + 2 files changed, 82 insertions(+), 67 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 21acfca0f..90147a43b 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -104,7 +104,7 @@ public: private: std::vector mData; - virtual bool calculate(Ogre::Real time) + bool calculate(Ogre::Real time) const { if(mData.size() == 0) return true; @@ -144,16 +144,21 @@ public: , mData(data->mVis) { } + virtual void applyToNode(Ogre::Node *node, float time) const + { + bool vis = calculate(time); + setVisible(node, vis); + } + virtual Ogre::Real getValue() const { // Should not be called - return 1.0f; + return 0.0f; } virtual void setValue(Ogre::Real time) { - bool vis = calculate(time); - setVisible(mNode, vis); + Value::applyToNode(mNode, time); } }; @@ -170,6 +175,66 @@ public: Nif::Vector3KeyList mTranslations; Nif::FloatKeyList mScales; + static float interpKey(const Nif::FloatKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } + + static Ogre::Vector3 interpKey(const Nif::Vector3KeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::Vector3KeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } + + static Ogre::Quaternion interpKey(const Nif::QuaternionKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::QuaternionKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue); + } + return Ogre::Quaternion(); + } + public: Value(Ogre::Node *target, const Nif::NiKeyframeData *data) : NodeTargetValue(target) @@ -178,6 +243,16 @@ public: , mScales(data->mScales) { } + virtual void applyToNode(Ogre::Node *node, float time) const + { + if(mRotations.mKeys.size() > 0) + node->setOrientation(interpKey(mRotations.mKeys, time)); + if(mTranslations.mKeys.size() > 0) + node->setPosition(interpKey(mTranslations.mKeys, time)); + if(mScales.mKeys.size() > 0) + node->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); + } + virtual Ogre::Real getValue() const { // Should not be called @@ -186,69 +261,7 @@ public: virtual void setValue(Ogre::Real time) { - if(mRotations.mKeys.size() > 0) - { - if(time <= mRotations.mKeys.front().mTime) - mNode->setOrientation(mRotations.mKeys.front().mValue); - else if(time >= mRotations.mKeys.back().mTime) - mNode->setOrientation(mRotations.mKeys.back().mValue); - else - { - Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); - for(;iter != mRotations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); - break; - } - } - } - if(mTranslations.mKeys.size() > 0) - { - if(time <= mTranslations.mKeys.front().mTime) - mNode->setPosition(mTranslations.mKeys.front().mValue); - else if(time >= mTranslations.mKeys.back().mTime) - mNode->setPosition(mTranslations.mKeys.back().mValue); - else - { - Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); - for(;iter != mTranslations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::Vector3KeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); - break; - } - } - } - if(mScales.mKeys.size() > 0) - { - if(time <= mScales.mKeys.front().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); - else if(time >= mScales.mKeys.back().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); - else - { - Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); - for(;iter != mScales.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); - break; - } - } - } + Value::applyToNode(mNode, time); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index e3bb55064..b53815fa0 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -85,6 +85,8 @@ public: NodeTargetValue(Ogre::Node *target) : mNode(target) { } + virtual void applyToNode(Ogre::Node *node, float time) const = 0; + void setNode(Ogre::Node *target) { mNode = target; } Ogre::Node *getNode() const From 835ff8eb1eb36bc16cffaca85343ee86d1533275 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Apr 2013 17:13:27 -0700 Subject: [PATCH 322/817] Avoid creating an AnimationValue per ObjectList --- apps/openmw/mwrender/animation.cpp | 6 +++--- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8e5bd0108..56b601727 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -32,7 +32,8 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mPtr(ptr) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + , mPtr(ptr) , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) @@ -70,7 +71,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b mInsert = node->createChildSceneNode(); assert(mInsert); } - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : NifOgre::Loader::createObjectBase(mInsert, model)); @@ -145,7 +145,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b for(size_t i = 0;i < objlist.mControllers.size();i++) { if(objlist.mControllers[i].getSource().isNull()) - objlist.mControllers[i].setSource(ctrlval); + objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } if(!mCurrentControllers || (*mCurrentControllers).size() == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index db2195c34..d3cb6bebb 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,6 +38,7 @@ protected: mAnimation->mCurrentTime = value; } }; + Ogre::SharedPtr > mAnimationBaseValuePtr; MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; From 19325f9d40944df8c6b312d309469e59e3c6c520 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 21 Apr 2013 11:41:09 -0700 Subject: [PATCH 323/817] fixed the type of iterator uses in MWWorld::Store The containers type used to declare some iterators was not an exact match for the type of the container the iterator was being initialized from. This was causing build failure on windows. --- apps/openmw/mwworld/store.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fb3f8c482..2bd61c2b0 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -475,7 +475,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -493,7 +493,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -534,7 +534,7 @@ namespace MWWorld void setUp() { //typedef std::vector::iterator Iterator; - typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef DynamicExt::iterator ExtIterator; typedef std::map::iterator IntIterator; //std::sort(mInt.begin(), mInt.end(), RecordCmp()); From 8bf1149cec0da1e8f7c59089c01b8804c9897cf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Apr 2013 21:24:48 +0200 Subject: [PATCH 324/817] Fix activation not working sometimes The current player cell was only being updated when the reference was not empty, causing it to incorrectly detect a cell change the first time something was activated in a newly visited cell, immediately closing the opened dialogue again. --- apps/openmw/mwgui/referenceinterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 66e036d92..86a85be18 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -18,17 +18,17 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - if (mPtr.isEmpty()) - return; - MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) - || mPtr.getRefData().getCount() == 0) + || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) { - mPtr = MWWorld::Ptr(); - onReferenceUnavailable(); + if (!mPtr.isEmpty()) + { + mPtr = MWWorld::Ptr(); + onReferenceUnavailable(); + } } mCurrentPlayerCell = playerCell; From d7c9df16f81ceebc7ee5da0b5242d33814a7e85e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 18:32:34 -0700 Subject: [PATCH 325/817] Store the current animation group --- apps/openmw/mwrender/animation.cpp | 3 ++- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 56b601727..ea27cbb5e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -441,9 +441,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; - mAnimVelocity = 0.0f; + mAnimVelocity = 0.0f; if(mNonAccumRoot) calcAnimVelocity(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d3cb6bebb..472a6289c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -53,6 +53,7 @@ protected: Ogre::Vector3 mLastPosition; Ogre::Animation *mCurrentAnim; + std::string mCurrentGroup; std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; From 6c85d6763aec95b2f3367fea90437f4e818042e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 18:38:25 -0700 Subject: [PATCH 326/817] Pass "loop stop" to the character controller --- apps/openmw/mwmechanics/character.cpp | 9 +++++++++ apps/openmw/mwrender/animation.cpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 02a5aa100..16d811528 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -150,6 +150,15 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::markerEvent(float time, const std::string &evt) { + if(evt == "loop stop") + { + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start", "stop", false); + } + return; + } if(evt == "stop") { if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ea27cbb5e..68fae99dd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -409,10 +409,10 @@ bool Animation::handleEvent(float time, const std::string &evt) reset("loop start"); if(mCurrentTime >= time) return false; + return true; } - return true; } - if(evt == "stop") + else if(evt == "stop") { if(mLooping) { From 7d59340ed6c27b4b895e9e9b7200c35bc612714c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 22:13:49 -0700 Subject: [PATCH 327/817] Don't clip out the group name from the textkeys --- apps/openmw/mwrender/animation.cpp | 39 +++++++++++++++++++----------- components/nifogre/skeleton.cpp | 12 +-------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 68fae99dd..2f2ffccb5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -243,14 +243,16 @@ void Animation::calcAnimVelocity() if(track && track->getNumKeyFrames() > 1) { + const std::string loopstart = mCurrentGroup+": loop start"; + const std::string loopstop = mCurrentGroup+": loop stop"; float loopstarttime = 0.0f; float loopstoptime = mCurrentAnim->getLength(); NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); while(keyiter != mCurrentKeys->end()) { - if(keyiter->second == "loop start") + if(keyiter->second == loopstart) loopstarttime = keyiter->first; - else if(keyiter->second == "loop stop") + else if(keyiter->second == loopstop) { loopstoptime = keyiter->first; break; @@ -383,12 +385,6 @@ void Animation::reset(const std::string &start, const std::string &stop) bool Animation::handleEvent(float time, const std::string &evt) { - if(evt == "start" || evt == "loop start") - { - /* Do nothing */ - return true; - } - if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -402,21 +398,36 @@ bool Animation::handleEvent(float time, const std::string &evt) return true; } - if(evt == "loop stop") + if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || + evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + { + // Not ours + return true; + } + size_t off = mCurrentGroup.size()+2; + size_t len = evt.size() - off; + + if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) + { + /* Do nothing */ + return true; + } + + if(evt.compare(off, len, "loop stop") == 0) { if(mLooping) { - reset("loop start"); + reset(mCurrentGroup+": loop start"); if(mCurrentTime >= time) return false; return true; } } - else if(evt == "stop") + else if(evt.compare(off, len, "stop") == 0) { if(mLooping) { - reset("loop start"); + reset(mCurrentGroup+": loop start"); if(mCurrentTime >= time) return false; return true; @@ -424,7 +435,7 @@ bool Animation::handleEvent(float time, const std::string &evt) // fall-through } if(mController) - mController->markerEvent(time, evt); + mController->markerEvent(time, evt.substr(off)); return true; } @@ -455,7 +466,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!found) throw std::runtime_error("Failed to find animation "+groupname); - reset(start, stop); + reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); setLooping(loop); mPlaying = true; } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 75bc90715..5eb043614 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -282,17 +282,7 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - TextKeyMap::const_iterator insiter(keyiter); - TextKeyMap groupkeys; - do { - sep = insiter->second.find(':'); - if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); - else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first, insiter->second)); - } while(insiter++ != lastkeyiter); - + TextKeyMap groupkeys(keyiter, ++lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 2345b5e8b3d7ebe69ef901098ac9d4603973ad09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 22:56:40 -0700 Subject: [PATCH 328/817] Avoid storing text keys for each animation --- apps/openmw/mwrender/animation.cpp | 15 +++------------ apps/openmw/mwrender/animation.hpp | 1 - components/nifogre/ogrenifloader.hpp | 2 ++ components/nifogre/skeleton.cpp | 7 +------ 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2f2ffccb5..d51a30a77 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -121,24 +121,15 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b Ogre::Bone *bone = boneiter.getNext(); Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; + if(data.isEmpty()) continue; + objlist.mTextKeys[bone->getHandle()] = Ogre::any_cast(data); if(!mNonAccumRoot) { mAccumRoot = mInsert; mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); } - for(int i = 0;i < skel->getNumAnimations();i++) - { - Ogre::Animation *anim = skel->getAnimation(i); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); - if(!groupdata.isEmpty()) - mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); - } - break; } } @@ -451,7 +442,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con { Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); mCurrentAnim = skel->getAnimation(groupname); - mCurrentKeys = &mTextKeys[groupname]; + mCurrentKeys = &iter->mTextKeys.begin()->second; mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 472a6289c..b60bd21a8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -46,7 +46,6 @@ protected: Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; std::vector mObjectLists; - std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index b53815fa0..8e220ea38 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -50,6 +50,8 @@ struct ObjectList { // bones in the mSkelBase which are NiCamera nodes. std::vector mCameras; + std::map mTextKeys; + std::vector > mControllers; ObjectList() : mSkelBase(0) diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 5eb043614..3660be81b 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -193,6 +193,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); animroot = bone; + bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(textkeys)); } e = e->extra; } @@ -255,9 +256,6 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) return; } - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); - bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); - std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) @@ -281,9 +279,6 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) } buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - - TextKeyMap groupkeys(keyiter, ++lastkeyiter); - bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 56b871e362724008c8bd4c5a686f63ce730f2a36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Apr 2013 07:57:53 +0200 Subject: [PATCH 329/817] Rank condition should always fail if NPC is not in a faction --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 78969ffd0..52c7bd4f3 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -73,6 +73,11 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (iter->second < info.mData.mRank) return false; } + else if (info.mData.mRank != -1) + { + // if there is a rank condition, but the NPC is not in a faction, always fail + return false; + } // Gender if (!isCreature) From a3511c62cf2c120636b4960f34f0a4973292d1c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 00:01:30 -0700 Subject: [PATCH 330/817] Don't store textkeys in user object bindings It's a bit unwieldy to have them stored in the 'skeleton master' instead of the skeleton instance. And although the text keys are extracted for each created instance now, this shouldn't be much worse than the multimap copying going on before. Plus, proper serialization can help for future optimizations. --- apps/openmw/mwrender/animation.cpp | 16 +++------------- components/nifogre/ogrenifloader.cpp | 10 +++++++++- components/nifogre/skeleton.cpp | 11 +++++------ components/nifogre/skeleton.hpp | 3 +-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d51a30a77..31f54107e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -97,9 +97,9 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); if(mSkelBase != objlist.mSkelBase) { - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < objlist.mControllers.size();i++) { NifOgre::NodeTargetValue *dstval; @@ -114,23 +114,13 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b } } - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); - boneiter = skel->getBoneIterator(); - while(boneiter.hasMoreElements()) + if(objlist.mTextKeys.size() > 0) { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty()) continue; - - objlist.mTextKeys[bone->getHandle()] = Ogre::any_cast(data); if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); } - - break; } } for(size_t i = 0;i < objlist.mControllers.size();i++) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 90147a43b..97dfc59ef 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -649,7 +649,14 @@ class NIFObjectLoader Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiStringExtraData) + if(e->recType == Nif::RC_NiTextKeyExtraData) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); + objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk); + } + else if(e->recType == Nif::RC_NiStringExtraData) { const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information @@ -661,6 +668,7 @@ class NIFObjectLoader flags |= 0x80000000; } } + e = e->extra; } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 3660be81b..1809212a7 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -193,7 +193,6 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); animroot = bone; - bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(textkeys)); } e = e->extra; } @@ -287,16 +286,16 @@ Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, con { /* We need to be a little aggressive here, since some NIFs have a crap-ton * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: - * There are no bones used for skinning, there are no controllers on non- - * NiTriShape nodes, there are no nodes named "AttachLight", and the tree - * consists of NiNode, NiTriShape, and RootCollisionNode types only. + * There are no bones used for skinning, there are no controllers, there + * are no nodes named "AttachLight", and the tree consists of NiNode, + * NiTriShape, and RootCollisionNode types only. */ if(!node->boneTrafo) { - if(node->recType == Nif::RC_NiTriShape) - return Ogre::SkeletonPtr(); if(node->controller.empty() && node->name != "AttachLight") { + if(node->recType == Nif::RC_NiTriShape) + return Ogre::SkeletonPtr(); if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) { const Nif::NiNode *ninode = static_cast(node); diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp index c69c2a12f..e71dcfb15 100644 --- a/components/nifogre/skeleton.hpp +++ b/components/nifogre/skeleton.hpp @@ -37,8 +37,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader } static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); - - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); // Lookup to retrieve an Ogre bone handle for a given Nif record index @@ -48,6 +46,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader static LoaderMap sLoaders; public: + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void loadResource(Ogre::Resource *resource); static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); From a7776e124cda07bc69bae504eebe6ccdb14bb07f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 00:22:31 -0700 Subject: [PATCH 331/817] Only set mNonAccumRoot from mSkelBase --- apps/openmw/mwrender/animation.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 31f54107e..54416c45a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,7 +98,15 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b boneiter.getNext()->setManuallyControlled(true); Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mSkelBase != objlist.mSkelBase) + if(mSkelBase == objlist.mSkelBase) + { + if(objlist.mTextKeys.size() > 0) + { + mAccumRoot = mInsert; + mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); + } + } + else { for(size_t i = 0;i < objlist.mControllers.size();i++) { @@ -113,15 +121,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b dstval->setNode(bone); } } - - if(objlist.mTextKeys.size() > 0) - { - if(!mNonAccumRoot) - { - mAccumRoot = mInsert; - mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); - } - } } for(size_t i = 0;i < objlist.mControllers.size();i++) { From a608e7ed06883ebc2b0ae09702bc133ffc2b1095 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 22 Apr 2013 09:56:11 +0200 Subject: [PATCH 332/817] updated changelog once more --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index d5a5dcc18..c033f9547 100644 --- a/readme.txt +++ b/readme.txt @@ -137,6 +137,8 @@ Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon Bug #725: Auto calculate stats +Bug #728: Failure to open container and talk dialogue +Bug #731: Crash with Mush-Mere's "background" topic Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From 9485a4aa6df48e9370b87a9bee5aec812cdca003 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 01:40:41 -0700 Subject: [PATCH 333/817] Look through the whole animation stack to find the "velocity" --- apps/openmw/mwrender/animation.cpp | 55 +++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 +-- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 54416c45a..d71b33cdd 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -209,26 +209,26 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -void Animation::calcAnimVelocity() +float Animation::calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, const std::string &groupname, const NifOgre::TextKeyMap *keys) { const Ogre::NodeAnimationTrack *track = 0; - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); while(!track && trackiter.hasMoreElements()) { const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + if(cur->getAssociatedNode()->getName() == bonename) track = cur; } if(track && track->getNumKeyFrames() > 1) { - const std::string loopstart = mCurrentGroup+": loop start"; - const std::string loopstop = mCurrentGroup+": loop stop"; + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; float loopstarttime = 0.0f; - float loopstoptime = mCurrentAnim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); - while(keyiter != mCurrentKeys->end()) + float loopstoptime = anim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); + while(keyiter != keys->end()) { if(keyiter->second == loopstart) loopstarttime = keyiter->first; @@ -245,13 +245,15 @@ void Animation::calcAnimVelocity() Ogre::TransformKeyFrame startkf(0, loopstarttime); Ogre::TransformKeyFrame endkf(0, loopstoptime); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstoptime), &endkf); - mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); + return startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); } } + + return 0.0f; } static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) @@ -423,27 +425,34 @@ bool Animation::handleEvent(float time, const std::string &evt) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { - bool found = false; + bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); - mCurrentAnim = skel->getAnimation(groupname); - mCurrentKeys = &iter->mTextKeys.begin()->second; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; + Ogre::Animation *anim = skel->getAnimation(groupname); + const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; + if(!foundanim) + { + mCurrentAnim = anim; + mCurrentKeys = keys; + mCurrentGroup = groupname; + mCurrentControllers = &iter->mControllers; - mAnimVelocity = 0.0f; - if(mNonAccumRoot) - calcAnimVelocity(); + mAnimVelocity = 0.0f; + foundanim = true; + } - found = true; - break; + if(!mNonAccumRoot) + break; + + mAnimVelocity = calcAnimVelocity(anim, mNonAccumRoot->getName(), groupname, keys); + if(mAnimVelocity > 0.0f) break; } } - if(!found) + if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b60bd21a8..cd2523b63 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -54,7 +54,7 @@ protected: std::string mCurrentGroup; std::vector > *mCurrentControllers; - NifOgre::TextKeyMap *mCurrentKeys; + const NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -65,7 +65,8 @@ protected: float mAnimVelocity; float mAnimSpeedMult; - void calcAnimVelocity(); + static float calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, + const std::string &groupname, const NifOgre::TextKeyMap *keys); /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ From d936291dbf2b7c9e5240aad64b1d338aed2207df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 02:53:32 -0700 Subject: [PATCH 334/817] Remove an unused ostream operator<< --- components/nifogre/ogrenifloader.cpp | 9 --------- components/nifogre/ogrenifloader.hpp | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 97dfc59ef..dc6bb8d24 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -44,15 +44,6 @@ #include "material.hpp" #include "mesh.hpp" -namespace std -{ - -// TODO: Do something useful -ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) -{ return o; } - -} - namespace NifOgre { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 8e220ea38..d0ff94217 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -98,14 +98,4 @@ typedef Ogre::SharedPtr > NodeTargetValueRealPtr; } -namespace std -{ - -// These operators allow extra data types to be stored in an Ogre::Any -// object, which can then be stored in user object bindings on the nodes - -ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&); - -} - #endif From 59137d93c99bdd9795a0dd0be7d3e9d4e63a2bb0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 03:24:02 -0700 Subject: [PATCH 335/817] Partially handle NiGeomMorpherController The morphs aren't actually applied yet, but the Ogre controller is set up so all that has to be done is to implement the setValue method. --- components/nifogre/mesh.cpp | 14 +++++++++ components/nifogre/ogrenifloader.cpp | 45 +++++++++++++++++++++++++++- components/nifogre/skeleton.cpp | 3 +- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c3..851160de2 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -116,6 +116,20 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape std::vector srcNorms = data->normals; Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; bool vertShadowBuffer = false; + + if(!shape->controller.empty()) + { + Nif::ControllerPtr ctrl = shape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + break; + } + } while(!(ctrl=ctrl->next).empty()); + } + if(skin != NULL) { vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index dc6bb8d24..942b3858a 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -293,7 +293,7 @@ public: } public: - Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data) + Value(const Ogre::MaterialPtr &material, const Nif::NiUVData *data) : mMaterial(material) , mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) @@ -363,6 +363,36 @@ public: typedef DefaultFunction Function; }; +class GeomMorpherController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::SubEntity *mSubEntity; + std::vector mMorphs; + + public: + Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data) + : mSubEntity(subent) + , mMorphs(data->mMorphs) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 0.0f; + } + + virtual void setValue(Ogre::Real value) + { + // TODO: Implement + } + }; + + typedef DefaultFunction Function; +}; + /** Object creator for NIFs. This is the main class responsible for creating * "live" Ogre objects (entities, particle systems, controllers, etc) from @@ -429,6 +459,19 @@ class NIFObjectLoader objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } + else if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); + + Ogre::SubEntity *subent = entity->getSubEntity(0); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(subent, geom->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } ctrl = ctrl->next; } } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 1809212a7..1306d037c 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -179,7 +179,8 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, ctrls.push_back(static_cast(ctrl.getPtr())); else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController + ctrl->recType == Nif::RC_NiUVController || + ctrl->recType == Nif::RC_NiGeomMorpherController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; From adc6a948c7ed308c57c5996c57c8227c91d4af99 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 03:41:38 -0700 Subject: [PATCH 336/817] Add methods to get the rotation, translation, and scale from a NodeTargetValue --- components/nifogre/ogrenifloader.cpp | 41 ++++++++++++++++++++-------- components/nifogre/ogrenifloader.hpp | 4 ++- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 942b3858a..451993cf4 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -135,11 +135,14 @@ public: , mData(data->mVis) { } - virtual void applyToNode(Ogre::Node *node, float time) const - { - bool vis = calculate(time); - setVisible(node, vis); - } + virtual Ogre::Quaternion getRotation(float time) const + { return Ogre::Quaternion(); } + + virtual Ogre::Vector3 getTranslation(float time) const + { return Ogre::Vector3(0.0f); } + + virtual Ogre::Vector3 getScale(float time) const + { return Ogre::Vector3(1.0f); } virtual Ogre::Real getValue() const { @@ -149,7 +152,8 @@ public: virtual void setValue(Ogre::Real time) { - Value::applyToNode(mNode, time); + bool vis = calculate(time); + setVisible(mNode, vis); } }; @@ -223,7 +227,7 @@ public: float a = (time-last->mTime) / (iter->mTime-last->mTime); return Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue); } - return Ogre::Quaternion(); + return keys.back().mValue; } public: @@ -234,14 +238,25 @@ public: , mScales(data->mScales) { } - virtual void applyToNode(Ogre::Node *node, float time) const + virtual Ogre::Quaternion getRotation(float time) const { if(mRotations.mKeys.size() > 0) - node->setOrientation(interpKey(mRotations.mKeys, time)); + return interpKey(mRotations.mKeys, time); + return Ogre::Quaternion(); + } + + virtual Ogre::Vector3 getTranslation(float time) const + { if(mTranslations.mKeys.size() > 0) - node->setPosition(interpKey(mTranslations.mKeys, time)); + return interpKey(mTranslations.mKeys, time); + return Ogre::Vector3(0.0f); + } + + virtual Ogre::Vector3 getScale(float time) const + { if(mScales.mKeys.size() > 0) - node->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); + return Ogre::Vector3(interpKey(mScales.mKeys, time)); + return Ogre::Vector3(1.0f); } virtual Ogre::Real getValue() const @@ -252,7 +267,9 @@ public: virtual void setValue(Ogre::Real time) { - Value::applyToNode(mNode, time); + mNode->setOrientation(Value::getRotation(time)); + mNode->setPosition(Value::getTranslation(time)); + mNode->setScale(Value::getScale(time)); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index d0ff94217..40577e451 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -87,7 +87,9 @@ public: NodeTargetValue(Ogre::Node *target) : mNode(target) { } - virtual void applyToNode(Ogre::Node *node, float time) const = 0; + virtual Ogre::Quaternion getRotation(T value) const = 0; + virtual Ogre::Vector3 getTranslation(T value) const = 0; + virtual Ogre::Vector3 getScale(T value) const = 0; void setNode(Ogre::Node *target) { mNode = target; } From cc70c6263bf377f600d8af023985ec8a092c3f5a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 04:10:46 -0700 Subject: [PATCH 337/817] Use the NodeTargetValue for the NonAccum root --- apps/openmw/mwrender/animation.cpp | 114 ++++++++++------------------- apps/openmw/mwrender/animation.hpp | 4 +- 2 files changed, 42 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d71b33cdd..5700af3d6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -41,12 +41,12 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentAnim(NULL) , mCurrentControllers(NULL) , mCurrentKeys(NULL) , mCurrentTime(0.0f) , mPlaying(false) , mLooping(false) + , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { @@ -209,48 +209,31 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, const std::string &groupname, const NifOgre::TextKeyMap *keys) +float Animation::calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys) { - const Ogre::NodeAnimationTrack *track = 0; - - Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; + float loopstarttime = 0.0f; + float loopstoptime = std::numeric_limits::max(); + NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); + while(keyiter != keys->end()) { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == bonename) - track = cur; + if(keyiter->second == loopstart) + loopstarttime = keyiter->first; + else if(keyiter->second == loopstop) + { + loopstoptime = keyiter->first; + break; + } + keyiter++; } - if(track && track->getNumKeyFrames() > 1) + if(loopstoptime > loopstarttime) { - const std::string loopstart = groupname+": loop start"; - const std::string loopstop = groupname+": loop stop"; - float loopstarttime = 0.0f; - float loopstoptime = anim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); - while(keyiter != keys->end()) - { - if(keyiter->second == loopstart) - loopstarttime = keyiter->first; - else if(keyiter->second == loopstop) - { - loopstoptime = keyiter->first; - break; - } - keyiter++; - } + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(loopstarttime); + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(loopstarttime); - if(loopstoptime > loopstarttime) - { - Ogre::TransformKeyFrame startkf(0, loopstarttime); - Ogre::TransformKeyFrame endkf(0, loopstoptime); - - track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstoptime), &endkf); - - return startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); - } + return startpos.distance(endpos) / (loopstoptime-loopstarttime); } return 0.0f; @@ -298,20 +281,8 @@ Ogre::Vector3 Animation::updatePosition() { Ogre::Vector3 posdiff; - Ogre::TransformKeyFrame kf(0, mCurrentTime); - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *track = trackiter.getNext(); - if(track->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - { - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); - break; - } - } - /* Get the non-accumulation root's difference from the last update. */ - posdiff = (kf.getTranslate() - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -344,24 +315,9 @@ void Animation::reset(const std::string &start, const std::string &stop) mStopKey--; } - if(mNonAccumRoot) - { - const Ogre::NodeAnimationTrack *track = 0; - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - track = cur; - } - - if(track) - { - Ogre::TransformKeyFrame kf(0, mCurrentTime); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); - mLastPosition = kf.getTranslate() * mAccumulate; - } - } + if(mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * + mAccumulate; } @@ -431,24 +387,34 @@ void Animation::play(const std::string &groupname, const std::string &start, con { if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); - Ogre::Animation *anim = skel->getAnimation(groupname); const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + for(size_t i = 0;i < iter->mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + if(!foundanim) { - mCurrentAnim = anim; mCurrentKeys = keys; mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; - + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; + foundanim = true; } if(!mNonAccumRoot) break; - mAnimVelocity = calcAnimVelocity(anim, mNonAccumRoot->getName(), groupname, keys); + mAnimVelocity = calcAnimVelocity(nonaccumctrl, groupname, keys); if(mAnimVelocity > 0.0f) break; } } @@ -469,7 +435,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) Ogre::Vector3 movement(0.0f); timepassed *= mAnimSpeedMult; - while(mCurrentAnim && mPlaying) + while(!mCurrentGroup.empty() && mPlaying) { float targetTime = mCurrentTime + timepassed; if(mNextKey->first > targetTime) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cd2523b63..92f636d0a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -50,7 +50,6 @@ protected: Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - Ogre::Animation *mCurrentAnim; std::string mCurrentGroup; std::vector > *mCurrentControllers; @@ -62,10 +61,11 @@ protected: bool mPlaying; bool mLooping; + NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; - static float calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, + static float calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys); /* Updates a skeleton instance so that all bones matching the source skeleton (based on From bb64efc18e9252292b82f3540e487bb14b22901e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 05:08:52 -0700 Subject: [PATCH 338/817] Improve looping behavior --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 78 ++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 +- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 16d811528..4684ca6ea 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5700af3d6..d065195ad 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -293,36 +293,51 @@ Ogre::Vector3 Animation::updatePosition() void Animation::reset(const std::string &start, const std::string &stop) { + std::string tag = mCurrentGroup+": "+start; mStartKey = mCurrentKeys->begin(); - - while(mStartKey != mCurrentKeys->end() && mStartKey->second != start) + while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) mStartKey++; - if(mStartKey != mCurrentKeys->end()) - mCurrentTime = mStartKey->first; - else + if(mStartKey == mCurrentKeys->end() && tag == "loop start") { + tag = mCurrentGroup+": start"; mStartKey = mCurrentKeys->begin(); - mCurrentTime = mStartKey->first; + while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) + mStartKey++; } - mNextKey = mStartKey; + if(mStartKey == mCurrentKeys->end()) + mStartKey = mCurrentKeys->begin(); - if(stop.length() > 0) - { - mStopKey = mStartKey; - while(mStopKey != mCurrentKeys->end() && mStopKey->second != stop) - mStopKey++; - if(mStopKey == mCurrentKeys->end()) - mStopKey--; - } + tag = mCurrentGroup+": "+stop; + mStopKey = mStartKey; + while(mStopKey != mCurrentKeys->end() && mStopKey->second != tag) + mStopKey++; + if(mStopKey == mCurrentKeys->end()) + mStopKey--; + + mCurrentTime = mStartKey->first; + mLoopStartKey = mStartKey; + mNextKey = mStartKey; + ++mNextKey; if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * - mAccumulate; + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; +} + +void Animation::doLoop() +{ + mCurrentTime = mLoopStartKey->first; + mNextKey = mLoopStartKey; + ++mNextKey; + if(mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; } -bool Animation::handleEvent(float time, const std::string &evt) +bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) { + float time = key->first; + const std::string &evt = key->second; + if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -347,25 +362,15 @@ bool Animation::handleEvent(float time, const std::string &evt) if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - /* Do nothing */ + mLoopStartKey = key; return true; } - if(evt.compare(off, len, "loop stop") == 0) + if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { if(mLooping) { - reset(mCurrentGroup+": loop start"); - if(mCurrentTime >= time) - return false; - return true; - } - } - else if(evt.compare(off, len, "stop") == 0) - { - if(mLooping) - { - reset(mCurrentGroup+": loop start"); + doLoop(); if(mCurrentTime >= time) return false; return true; @@ -421,7 +426,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); - reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); + reset(start, stop); setLooping(loop); mPlaying = true; } @@ -446,18 +451,15 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) break; } - float time = mNextKey->first; - const std::string &evt = mNextKey->second; - mNextKey++; - - mCurrentTime = time; + NifOgre::TextKeyMap::const_iterator key(mNextKey++); + mCurrentTime = key->first; if(mNonAccumRoot) movement += updatePosition(); mPlaying = (mLooping || mStopKey->first > mCurrentTime); timepassed = targetTime - mCurrentTime; - if(!handleEvent(time, evt)) + if(!handleTextKey(key)) break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 92f636d0a..0d81cf3b4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,6 +55,7 @@ protected: std::vector > *mCurrentControllers; const NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; float mCurrentTime; @@ -82,7 +83,9 @@ protected: */ void reset(const std::string &start, const std::string &stop=std::string()); - bool handleEvent(float time, const std::string &evt); + void doLoop(); + + bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); From a2fc43c7df22786b4d022be550928c2478a16c24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 20:41:54 -0700 Subject: [PATCH 339/817] Use reset to check that the animation exists and has the right markers --- apps/openmw/mwrender/animation.cpp | 123 ++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 10 ++- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d065195ad..a17d225e9 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -209,14 +209,14 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys) +float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) { const std::string loopstart = groupname+": loop start"; const std::string loopstop = groupname+": loop stop"; float loopstarttime = 0.0f; - float loopstoptime = std::numeric_limits::max(); - NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); - while(keyiter != keys->end()) + float loopstoptime = 0.0f; + NifOgre::TextKeyMap::const_iterator keyiter = keys.begin(); + while(keyiter != keys.end()) { if(keyiter->second == loopstart) loopstarttime = keyiter->first; @@ -291,36 +291,44 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -void Animation::reset(const std::string &start, const std::string &stop) +bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { - std::string tag = mCurrentGroup+": "+start; - mStartKey = mCurrentKeys->begin(); - while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) - mStartKey++; - if(mStartKey == mCurrentKeys->end() && tag == "loop start") + std::string tag = groupname+": "+start; + NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); + while(startkey != keys.end() && startkey->second != tag) + startkey++; + if(startkey == keys.end() && tag == "loop start") { - tag = mCurrentGroup+": start"; - mStartKey = mCurrentKeys->begin(); - while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) - mStartKey++; + tag = groupname+": start"; + startkey = keys.begin(); + while(startkey != keys.end() && startkey->second != tag) + startkey++; } - if(mStartKey == mCurrentKeys->end()) - mStartKey = mCurrentKeys->begin(); + if(startkey == keys.end()) + return false; - tag = mCurrentGroup+": "+stop; - mStopKey = mStartKey; - while(mStopKey != mCurrentKeys->end() && mStopKey->second != tag) - mStopKey++; - if(mStopKey == mCurrentKeys->end()) - mStopKey--; + tag = groupname+": "+stop; + NifOgre::TextKeyMap::const_iterator stopkey(startkey); + while(stopkey != keys.end() && stopkey->second != tag) + stopkey++; + if(stopkey == keys.end()) + return false; - mCurrentTime = mStartKey->first; + if(startkey == stopkey) + return false; + + mStartKey = startkey; mLoopStartKey = mStartKey; + mStopKey = stopkey; mNextKey = mStartKey; ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mCurrentTime = mStartKey->first; + + if(nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + + return true; } void Animation::doLoop() @@ -390,45 +398,46 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + for(size_t i = 0;i < iter->mControllers.size();i++) { - const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - - if(!foundanim) - { - mCurrentKeys = keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - - foundanim = true; - } - - if(!mNonAccumRoot) + nonaccumctrl = dstval; break; - - mAnimVelocity = calcAnimVelocity(nonaccumctrl, groupname, keys); - if(mAnimVelocity > 0.0f) break; + } } + + if(!foundanim) + { + if(!reset(keys, nonaccumctrl, groupname, start, stop)) + continue; + mCurrentKeys = &keys; + mCurrentGroup = groupname; + mCurrentControllers = &iter->mControllers; + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + + setLooping(loop); + mPlaying = true; + + foundanim = true; + } + + if(!mNonAccumRoot) + break; + + mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); + if(mAnimVelocity > 0.0f) break; } if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); - - reset(start, stop); - setLooping(loop); - mPlaying = true; } catch(std::exception &e) { std::cerr<< e.what() < *nonaccumctrl, - const std::string &groupname, const NifOgre::TextKeyMap *keys); + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, + NifOgre::NodeTargetValue *nonaccumctrl, + const std::string &groupname); /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ @@ -79,9 +80,10 @@ protected: /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If - * the marker is not found, it resets to the beginning or end respectively. + * the marker is not found, or if the markers are the same, it returns + * false. */ - void reset(const std::string &start, const std::string &stop=std::string()); + bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); void doLoop(); From 7279e015e9e76a0dec940f2f10fd2948c39500f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 20:59:55 -0700 Subject: [PATCH 340/817] Search the textkeys to check if an animation group exists --- apps/openmw/mwrender/animation.cpp | 19 ++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a17d225e9..b5f23b2c4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,11 +169,28 @@ Ogre::Node *Animation::getNode(const std::string &name) } +NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) +{ + NifOgre::TextKeyMap::const_iterator iter(keys.begin()); + for(;iter != keys.end();iter++) + { + if(iter->second.compare(0, groupname.size(), groupname) == 0 && + iter->second.compare(groupname.size(), 2, ": ") == 0) + break; + } + return iter; +} + + bool Animation::hasAnimation(const std::string &anim) { for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(anim)) + if(iter->mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + if(findGroupStart(keys, anim) != keys.end()) return true; } return false; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 06c2b485b..6393ee7c9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -78,6 +78,8 @@ protected: * returns the wanted movement vector from the previous update. */ Ogre::Vector3 updatePosition(); + static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); + /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If * the marker is not found, or if the markers are the same, it returns From c3ce49798a315c9fd8065b356f7fae87557c69cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 21:34:39 -0700 Subject: [PATCH 341/817] Fix animation velocity calculation --- apps/openmw/mwrender/animation.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b5f23b2c4..45f2a6fcb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -228,29 +228,31 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) { + const std::string start = groupname+": start"; const std::string loopstart = groupname+": loop start"; const std::string loopstop = groupname+": loop stop"; - float loopstarttime = 0.0f; - float loopstoptime = 0.0f; - NifOgre::TextKeyMap::const_iterator keyiter = keys.begin(); + const std::string stop = groupname+": stop"; + float starttime = std::numeric_limits::max(); + float stoptime = 0.0f; + NifOgre::TextKeyMap::const_iterator keyiter(keys.begin()); while(keyiter != keys.end()) { - if(keyiter->second == loopstart) - loopstarttime = keyiter->first; - else if(keyiter->second == loopstop) + if(keyiter->second == start || keyiter->second == loopstart) + starttime = keyiter->first; + else if(keyiter->second == loopstop || keyiter->second == stop) { - loopstoptime = keyiter->first; + stoptime = keyiter->first; break; } keyiter++; } - if(loopstoptime > loopstarttime) + if(stoptime > starttime) { - Ogre::Vector3 startpos = nonaccumctrl->getTranslation(loopstarttime); - Ogre::Vector3 endpos = nonaccumctrl->getTranslation(loopstarttime); + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime); + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime); - return startpos.distance(endpos) / (loopstoptime-loopstarttime); + return startpos.distance(endpos) / (stoptime-starttime); } return 0.0f; From 8782ae6976aa316a5394dd4e33c6cf0cd290779a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 23:35:50 -0700 Subject: [PATCH 342/817] Separate some Animation fields into a separate AnimLayer class --- apps/openmw/mwmechanics/character.cpp | 4 - apps/openmw/mwrender/animation.cpp | 179 +++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 52 ++++---- 3 files changed, 130 insertions(+), 105 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4684ca6ea..07f7b6940 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -304,11 +304,7 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) - { - if(mAnimation) - mAnimation->setLooping(loop); return; - } mState = state; if(!mAnimation) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 45f2a6fcb..4c5a86985 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,6 +18,32 @@ namespace MWRender { +Animation::AnimLayer::AnimLayer() + : mControllers(NULL) + , mTextKeys(NULL) + , mTime(0.0f) + , mPlaying(false) + , mLooping(false) +{ +} + + +Ogre::Real Animation::AnimationValue::getValue() const +{ + size_t idx = mIndex; + while(idx > 0 && mAnimation->mLayer[idx].mGroupName.empty()) + idx--; + if(!mAnimation->mLayer[idx].mGroupName.empty()) + return mAnimation->mLayer[idx].mTime; + return 0.0f; +} + +void Animation::AnimationValue::setValue(Ogre::Real value) +{ + mAnimation->mLayer[mIndex].mTime = value; +} + + void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) { for(size_t i = 0;i < objects.mParticles.size();i++) @@ -32,7 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) , mPtr(ptr) , mController(NULL) , mInsert(NULL) @@ -41,11 +67,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentControllers(NULL) - , mCurrentKeys(NULL) - , mCurrentTime(0.0f) - , mPlaying(false) - , mLooping(false) , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) @@ -127,9 +148,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } - - if(!mCurrentControllers || (*mCurrentControllers).size() == 0) - mCurrentControllers = &objlist.mControllers; } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -215,10 +233,6 @@ void Animation::setSpeed(float speed) mAnimSpeedMult = speed / mAnimVelocity; } -void Animation::setLooping(bool loop) -{ - mLooping = loop; -} void Animation::updatePtr(const MWWorld::Ptr &ptr) { @@ -301,7 +315,7 @@ Ogre::Vector3 Animation::updatePosition() Ogre::Vector3 posdiff; /* Get the non-accumulation root's difference from the last update. */ - posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -310,7 +324,7 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -336,31 +350,31 @@ bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue< if(startkey == stopkey) return false; - mStartKey = startkey; - mLoopStartKey = mStartKey; - mStopKey = stopkey; - mNextKey = mStartKey; - ++mNextKey; + mLayer[layeridx].mStartKey = startkey; + mLayer[layeridx].mLoopStartKey = startkey; + mLayer[layeridx].mStopKey = stopkey; + mLayer[layeridx].mNextKey = startkey; + mLayer[layeridx].mNextKey++; - mCurrentTime = mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; - if(nonaccumctrl) - mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + if(layeridx == 0 && nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; return true; } -void Animation::doLoop() +void Animation::doLoop(size_t layeridx) { - mCurrentTime = mLoopStartKey->first; - mNextKey = mLoopStartKey; - ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; + mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; + mLayer[layeridx].mNextKey++; + if(layeridx == 0 && mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } -bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) +bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key) { float time = key->first; const std::string &evt = key->second; @@ -378,27 +392,27 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) return true; } - if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || - evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + if(evt.compare(0, mLayer[layeridx].mGroupName.size(), mLayer[layeridx].mGroupName) != 0 || + evt.compare(mLayer[layeridx].mGroupName.size(), 2, ": ") != 0) { - // Not ours + // Not ours, skip it return true; } - size_t off = mCurrentGroup.size()+2; + size_t off = mLayer[layeridx].mGroupName.size()+2; size_t len = evt.size() - off; if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - mLoopStartKey = key; + mLayer[layeridx].mLoopStartKey = key; return true; } if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLooping) + if(mLayer[layeridx].mLooping) { - doLoop(); - if(mCurrentTime >= time) + doLoop(layeridx); + if(mLayer[layeridx].mTime >= time) return false; return true; } @@ -412,6 +426,9 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { + // TODO: parameterize this + size_t layeridx = 0; + try { bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ @@ -422,34 +439,40 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + if(layeridx == 0) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) + for(size_t i = 0;i < iter->mControllers.size();i++) { - nonaccumctrl = dstval; - break; + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } } } if(!foundanim) { - if(!reset(keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) continue; - mCurrentKeys = &keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; - setLooping(loop); - mPlaying = true; + if(layeridx == 0) + { + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + } foundanim = true; } - if(!mNonAccumRoot) + if(!nonaccumctrl) break; mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); @@ -463,37 +486,43 @@ void Animation::play(const std::string &groupname, const std::string &start, con } } -Ogre::Vector3 Animation::runAnimation(float timepassed) +Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - timepassed *= mAnimSpeedMult; - while(!mCurrentGroup.empty() && mPlaying) + duration *= mAnimSpeedMult; + for(size_t layeridx = 0;layeridx < sMaxLayers;layeridx++) { - float targetTime = mCurrentTime + timepassed; - if(mNextKey->first > targetTime) + if(mLayer[layeridx].mGroupName.empty()) + continue; + + float timepassed = duration; + while(mLayer[layeridx].mPlaying) { - mCurrentTime = targetTime; - if(mNonAccumRoot) + float targetTime = mLayer[layeridx].mTime + timepassed; + if(mLayer[layeridx].mNextKey->first > targetTime) + { + mLayer[layeridx].mTime = targetTime; + if(layeridx == 0 && mNonAccumRoot) + movement += updatePosition(); + break; + } + + NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); + mLayer[layeridx].mTime = key->first; + if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - break; + + mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + timepassed = targetTime - mLayer[layeridx].mTime; + + if(!handleTextKey(layeridx, key)) + break; } - - NifOgre::TextKeyMap::const_iterator key(mNextKey++); - mCurrentTime = key->first; - if(mNonAccumRoot) - movement += updatePosition(); - - mPlaying = (mLooping || mStopKey->first > mCurrentTime); - timepassed = targetTime - mCurrentTime; - - if(!handleTextKey(key)) - break; + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); } - for(size_t i = 0;i < (*mCurrentControllers).size();i++) - (*mCurrentControllers)[i].update(); - if(mSkelBase) { const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6393ee7c9..96138cf74 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -23,20 +23,15 @@ protected: { private: Animation *mAnimation; + size_t mIndex; public: - AnimationValue(Animation *anim) : mAnimation(anim) + AnimationValue(Animation *anim, size_t layeridx) + : mAnimation(anim), mIndex(layeridx) { } - virtual Ogre::Real getValue() const - { - return mAnimation->mCurrentTime; - } - - virtual void setValue(Ogre::Real value) - { - mAnimation->mCurrentTime = value; - } + virtual Ogre::Real getValue() const; + virtual void setValue(Ogre::Real value); }; Ogre::SharedPtr > mAnimationBaseValuePtr; @@ -51,21 +46,28 @@ protected: Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::string mCurrentGroup; - std::vector > *mCurrentControllers; - const NifOgre::TextKeyMap *mCurrentKeys; - NifOgre::TextKeyMap::const_iterator mStartKey; - NifOgre::TextKeyMap::const_iterator mLoopStartKey; - NifOgre::TextKeyMap::const_iterator mStopKey; - NifOgre::TextKeyMap::const_iterator mNextKey; - float mCurrentTime; - bool mPlaying; - bool mLooping; - NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + static const size_t sMaxLayers = 1; + struct AnimLayer { + std::string mGroupName; + std::vector > *mControllers; + const NifOgre::TextKeyMap *mTextKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; + NifOgre::TextKeyMap::const_iterator mNextKey; + + float mTime; + + bool mPlaying; + bool mLooping; + + AnimLayer(); + } mLayer[sMaxLayers]; + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname); @@ -85,11 +87,11 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(); + void doLoop(size_t layeridx); - bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); + bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); @@ -113,8 +115,6 @@ public: void setSpeed(float speed); - void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); From e3781769371e8c736bcf2643537c60cf6fe106f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 00:15:31 -0700 Subject: [PATCH 343/817] Don't update controllers that have already been updated --- apps/openmw/mwrender/animation.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4c5a86985..0166eb843 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -519,8 +519,23 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(!handleTextKey(layeridx, key)) break; } - for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) - (*(mLayer[layeridx].mControllers))[i].update(); + + bool updatectrls = true; + for(size_t i = layeridx-1;i < layeridx;i--) + { + if(mLayer[i].mGroupName.empty()) + continue; + if(mLayer[i].mControllers == mLayer[layeridx].mControllers) + { + updatectrls = false; + break; + } + } + if(updatectrls) + { + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); + } } if(mSkelBase) From afe7b3c64c4adafd112b4d151d8866ffefb4a725 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 10:56:55 +0200 Subject: [PATCH 344/817] added additional type argument to IdCollection::appendBlankRecord --- apps/opencs/model/world/idcollection.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 7052b300e..45b4961aa 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -16,6 +16,7 @@ #include #include "columnbase.hpp" +#include "universalid.hpp" namespace CSMWorld { @@ -53,7 +54,9 @@ namespace CSMWorld virtual void removeRows (int index, int count) = 0; - virtual void appendBlankRecord (const std::string& id) = 0; + virtual void appendBlankRecord (const std::string& id, + UniversalId::Type type = UniversalId::Type_None) = 0; + ///< \param type Will be ignored, unless the collection supports multiple record types virtual int searchId (const std::string& id) const = 0; ////< Search record with \a id. @@ -143,7 +146,9 @@ namespace CSMWorld virtual void removeRows (int index, int count) ; - virtual void appendBlankRecord (const std::string& id); + virtual void appendBlankRecord (const std::string& id, + UniversalId::Type type = UniversalId::Type_None); + ///< \param type Will be ignored, unless the collection supports multiple record types virtual int searchId (const std::string& id) const; ////< Search record with \a id. @@ -300,7 +305,8 @@ namespace CSMWorld } template - void IdCollection::appendBlankRecord (const std::string& id) + void IdCollection::appendBlankRecord (const std::string& id, + UniversalId::Type type) { ESXRecordT record; IdAccessorT().getId (record) = id; From 808718d96708d9833e7a8fe959de1e8823802039 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 11:21:21 +0200 Subject: [PATCH 345/817] added referenceable record types to UniversalId --- apps/opencs/model/world/universalid.cpp | 26 +++++++++++++++++++++++++ apps/opencs/model/world/universalid.hpp | 25 +++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index c0241bc38..bd1632e3e 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -29,6 +29,8 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, + "Referenceables" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -47,6 +49,30 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Activator, "Activator" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Potion, "Potion" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Apparatus, "Apparatus" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Armor, "Armor" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Book, "Book" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Clothing, "Clothing" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Container, "Container" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Creature, "Creature" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Door, "Door" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Ingredient, "Ingredient" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_CreatureLevelledList, + "Creature Levelled List" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_ItemLevelledList, + "Item Levelled List" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Light, "Light" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Lockpick, "Lockpick" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Miscellaneous, + "Miscellaneous" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Npc, "NPC" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Probe, "Probe" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Repair, "Repair" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Static, "Static" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Weapon, "Weapon" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 9b52aded1..2c4b14eaf 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -57,7 +57,30 @@ namespace CSMWorld Type_Spells, Type_Spell, Type_Cells, - Type_Cell + Type_Cell, + Type_Referenceables, + Type_Referenceable, + Type_Activator, + Type_Potion, + Type_Apparatus, + Type_Armor, + Type_Book, + Type_Clothing, + Type_Container, + Type_Creature, + Type_Door, + Type_Ingredient, + Type_CreatureLevelledList, + Type_ItemLevelledList, + Type_Light, + Type_Lockpick, + Type_Miscellaneous, + Type_Npc, + Type_Probe, + Type_Repair, + Type_Static, + Type_Weapon + }; private: From a17d17c19105557c88ff2cdcaca19df103f6fba6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 11:22:07 +0200 Subject: [PATCH 346/817] added additional type argument to IdCollection::load --- apps/opencs/model/world/idcollection.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 45b4961aa..7761929f3 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -79,7 +79,9 @@ namespace CSMWorld virtual const RecordBase& getRecord (int index) const = 0; - virtual void load (ESM::ESMReader& reader, bool base) = 0; + virtual void load (ESM::ESMReader& reader, bool base, + UniversalId::Type type = UniversalId::Type_None) = 0; + ///< \param type Will be ignored, unless the collection supports multiple record types }; ///< \brief Access to ID field in records @@ -171,7 +173,9 @@ namespace CSMWorld virtual const Record& getRecord (int index) const; - virtual void load (ESM::ESMReader& reader, bool base); + virtual void load (ESM::ESMReader& reader, bool base, + UniversalId::Type type = UniversalId::Type_None); + ///< \param type Will be ignored, unless the collection supports multiple record types void addColumn (Column *column); }; @@ -348,7 +352,8 @@ namespace CSMWorld } template - void IdCollection::load (ESM::ESMReader& reader, bool base) + void IdCollection::load (ESM::ESMReader& reader, bool base, + UniversalId::Type type) { std::string id = reader.getHNOString ("NAME"); From e4c5aac9664db105fde2b31b0973d5c7b483d80a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 02:48:11 -0700 Subject: [PATCH 347/817] Keep track of the animation layers a given object list is animating on This only tracks layers they explicitly animate on. They may animate on other layers as well, if nothing else is animating on them. --- apps/openmw/mwrender/activatoranimation.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 63 +++++++++++++++------ apps/openmw/mwrender/animation.hpp | 11 +++- apps/openmw/mwrender/creatureanimation.cpp | 2 +- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index c3a3045c2..4eb844607 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -22,7 +22,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) const std::string name = "meshes\\"+ref->mBase->mModel; addObjectList(mPtr.getRefData().getBaseNode(), name, false); - setRenderProperties(mObjectLists.back(), RV_Misc, RQG_Main, RQG_Alpha); + setRenderProperties(mObjects.back().mObjectList, RV_Misc, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0166eb843..98e2f9104 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,9 +78,9 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mObjectLists.size();i++) - destroyObjectList(sceneMgr, mObjectLists[i]); - mObjectLists.clear(); + for(size_t i = 0;i < mObjects.size();i++) + destroyObjectList(sceneMgr, mObjects[i].mObjectList); + mObjects.clear(); } } @@ -93,9 +93,13 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b assert(mInsert); } - mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : - NifOgre::Loader::createObjectBase(mInsert, model)); - NifOgre::ObjectList &objlist = mObjectLists.back(); + mObjects.push_back(ObjectInfo()); + ObjectInfo &obj = mObjects.back(); + obj.mActiveLayers = 0; + obj.mObjectList = (!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + + NifOgre::ObjectList &objlist = obj.mObjectList; if(objlist.mSkelBase) { if(!mSkelBase) @@ -202,12 +206,12 @@ NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::Tex bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) + for(std::vector::const_iterator iter(mObjects.begin());iter != mObjects.end();iter++) { - if(iter->mTextKeys.size() == 0) + if(iter->mObjectList.mTextKeys.size() == 0) continue; - const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + const NifOgre::TextKeyMap &keys = iter->mObjectList.mTextKeys.begin()->second; if(findGroupStart(keys, anim) != keys.end()) return true; } @@ -430,21 +434,45 @@ void Animation::play(const std::string &groupname, const std::string &start, con size_t layeridx = 0; try { + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) + for(std::vector::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) { - if(iter->mTextKeys.size() == 0) + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) continue; - const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; if(layeridx == 0) { - for(size_t i = 0;i < iter->mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); if(dstval && dstval->getNode() == mNonAccumRoot) { nonaccumctrl = dstval; @@ -459,7 +487,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con continue; mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mControllers = &objlist.mControllers; mLayer[layeridx].mLooping = loop; mLayer[layeridx].mPlaying = true; @@ -469,6 +497,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mAnimVelocity = 0.0f; } + iter->mActiveLayers |= (1<getSkeleton(); - for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) { - Ogre::Entity *ent = iter->mSkelBase; + Ogre::Entity *ent = iter->mObjectList.mSkelBase; if(!ent) continue; Ogre::SkeletonInstance *inst = ent->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 96138cf74..840c22ae4 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,9 +38,18 @@ protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; + struct ObjectInfo { + NifOgre::ObjectList mObjectList; + /* Bit-field specifying which animation layers this object list is + * explicitly animating on (1 = layer 0, 2 = layer 1, 4 = layer 2. + * etc). + */ + int mActiveLayers; + }; + Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; - std::vector mObjectLists; + std::vector mObjects; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 51632b2ee..97c28c0ae 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -25,7 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); addObjectList(mPtr.getRefData().getBaseNode(), model, false); - setRenderProperties(mObjectLists.back(), RV_Actors, RQG_Main, RQG_Alpha); + setRenderProperties(mObjects.back().mObjectList, RV_Actors, RQG_Main, RQG_Alpha); } } From cfccf0981dee740e725eb819d1dbb2cf00c66b2d Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 23 Apr 2013 13:24:06 +0400 Subject: [PATCH 348/817] update IndexedStore::setUp() for multiple datafile support --- apps/openmw/mwworld/store.hpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fb3f8c482..959b944e1 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -872,7 +872,28 @@ namespace MWWorld } void setUp() { - std::sort(mStatic.begin(), mStatic.end(), Compare()); + /// \note This method sorts indexed values for further + /// searches. Every loaded item is present in storage, but + /// latest loaded shadows any previous while searching. + /// If memory cost will be too high, it is possible to remove + /// unused values. + + Compare cmp; + + std::stable_sort(mStatic.begin(), mStatic.end(), cmp); + + typename std::vector::iterator first, next; + next = first = mStatic.begin(); + + while (first != mStatic.end() && ++next != mStatic.end()) { + while (next != mStatic.end() && !cmp(*first, *next)) { + ++next; + } + if (first != --next) { + std::swap(*first, *next); + } + first = ++next; + } } const T *search(int index) const { From c4806f01f850bbf18052659e45b222553b9f747c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 03:42:00 -0700 Subject: [PATCH 349/817] Use a separate list of controllers to update This should make it easier to figure out what controllers need to be updated for various animation sources and layers. --- apps/openmw/mwrender/animation.cpp | 220 ++++++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 3 + 2 files changed, 139 insertions(+), 84 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 98e2f9104..fbf5725c4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -71,6 +71,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + /* As long as we remain under 128 active controllers, we can avoid + * reallocations. */ + mActiveCtrls.reserve(128); } Animation::~Animation() @@ -179,6 +182,79 @@ void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::ui } +void Animation::updateActiveControllers() +{ + mActiveCtrls.clear(); + + /* First, get all controllers that don't target a node, or that target + * nodes that don't belong to any particular layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + std::vector >::const_iterator ctrl(obj->mObjectList.mControllers.begin()); + for(;ctrl != obj->mObjectList.mControllers.end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*if(getLayerByName(dstval->getNode()->getName()) >= 0)*/ + continue; + } + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + std::vector > *ctrls = NULL; + size_t layer = 0; + while(layer < sMaxLayers) + { + /* Now get controllers that target nodes that belong to this layer from + * whatever objectlist is active on this layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1<mObjectList.mControllers; + break; + } + } + + /* Check if any objectlists are active on subsequent layers. Include + * those layers if not. + */ + size_t nextlayer = layer+1; + for(;nextlayer < sMaxLayers;nextlayer++) + { + for(obj = mObjects.begin();obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1< >::const_iterator ctrl(ctrls->begin()); + for(;ctrl != ctrls->end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*ssize_t idx = getLayerByName(dstval->getNode()->getName()); + if(idx >= (ssize_t)layer && idx < (ssize_t)nextlayer)*/ + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + layer = nextlayer; + } +} + + Ogre::Node *Animation::getNode(const std::string &name) { if(mSkelBase) @@ -433,86 +509,76 @@ void Animation::play(const std::string &groupname, const std::string &start, con // TODO: parameterize this size_t layeridx = 0; - try { - for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) - iter->mActiveLayers &= ~(1<::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) + { + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + if(layeridx == 0) { - // Do not allow layer 0 to be disabled - assert(layeridx != 0); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + } - mLayer[layeridx].mGroupName.clear(); - mLayer[layeridx].mTextKeys = NULL; - mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; - mLayer[layeridx].mPlaying = false; + if(!foundanim) + { + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + continue; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &objlist.mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; if(layeridx == 0) { - mNonAccumCtrl = NULL; + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; } - return; + iter->mActiveLayers |= (1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) - { - NifOgre::ObjectList &objlist = iter->mObjectList; - if(objlist.mTextKeys.size() == 0) - continue; + if(!nonaccumctrl) + break; - const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) - { - for(size_t i = 0;i < objlist.mControllers.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - } - - if(!foundanim) - { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) - continue; - mLayer[layeridx].mGroupName = groupname; - mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; - mLayer[layeridx].mPlaying = true; - - if(layeridx == 0) - { - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - } - - iter->mActiveLayers |= (1< 0.0f) break; - } - if(!foundanim) - throw std::runtime_error("Failed to find animation "+groupname); - } - catch(std::exception &e) { - std::cerr<< e.what() < 0.0f) break; } + if(!foundanim) + std::cerr<< "Failed to find animation "<getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 840c22ae4..4860f44f5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -58,6 +58,7 @@ protected: NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; struct AnimLayer { @@ -107,6 +108,8 @@ protected: static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + void updateActiveControllers(); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); From 8c9e2e0ee9e24b444efa67f811ed8be1cd87fbcb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 05:34:08 -0700 Subject: [PATCH 350/817] Improve handling of reaching the stop animation text key --- apps/openmw/mwrender/animation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fbf5725c4..d98a32828 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -449,6 +449,7 @@ void Animation::doLoop(size_t layeridx) mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; mLayer[layeridx].mNextKey++; + mLayer[layeridx].mPlaying = true; if(layeridx == 0 && mNonAccumCtrl) mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } @@ -608,7 +609,7 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); timepassed = targetTime - mLayer[layeridx].mTime; if(!handleTextKey(layeridx, key)) From 44ac0a7c1856bf463f18ed435d554574745d4c50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Apr 2013 22:47:21 +0200 Subject: [PATCH 351/817] Use one vertex buffer for all UV coordinates --- components/nifogre/mesh.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c3..6d940deed 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -260,13 +260,24 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Texture UV coordinates size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) + if (numUVs) { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + + for(size_t i = 0; i < numUVs; i++) + decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + + vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + + std::vector allUVs; + allUVs.reserve(srcVerts.size()*numUVs); + for (size_t vert = 0; vertuvlist[i][vert]); + + vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); bind->setBinding(nextBuf++, vbuf); } From 634b0fd067a7c4ac65123be69dd29c0c4739be2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 17:57:40 -0700 Subject: [PATCH 352/817] Fix for controller delta time going below start time --- components/nifogre/ogrenifloader.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 451993cf4..95ba439d1 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -65,11 +65,7 @@ public: , mStopTime(ctrl->timeStop) { if(mDeltaInput) - { mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); - } } virtual Ogre::Real calculate(Ogre::Real value) @@ -77,6 +73,9 @@ public: if(mDeltaInput) { mDeltaCount += value*mFrequency; + if(mDeltaCount < mStartTime) + mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, + mStopTime - mStartTime); mDeltaCount = std::fmod(mDeltaCount - mStartTime, mStopTime - mStartTime) + mStartTime; return mDeltaCount; From 7e2995bc2f7b21f2335424e0d49e7d5231a673d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 19:43:26 -0700 Subject: [PATCH 353/817] Fix setting up active controllers --- apps/openmw/mwrender/animation.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d98a32828..cb54a0366 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -155,6 +155,8 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } + + mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -231,7 +233,7 @@ void Animation::updateActiveControllers() { for(obj = mObjects.begin();obj != mObjects.end();obj++) { - if((obj->mActiveLayers&(1<mActiveLayers&(1< Date: Tue, 23 Apr 2013 20:42:54 -0700 Subject: [PATCH 354/817] Don't create Ogre animations for skeletons --- components/nifogre/ogrenifloader.cpp | 28 +++- components/nifogre/skeleton.cpp | 220 ++------------------------- components/nifogre/skeleton.hpp | 4 +- 3 files changed, 37 insertions(+), 215 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 95ba439d1..e451326fe 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -676,6 +676,32 @@ class NIFObjectLoader } + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) + { + TextKeyMap textkeys; + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + return textkeys; + } + + static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags, int animflags, int partflags) @@ -704,7 +730,7 @@ class NIFObjectLoader const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk); + objectlist.mTextKeys[trgtid] = extractTextKeys(tk); } else if(e->recType == Nif::RC_NiStringExtraData) { diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 1306d037c..3aec920fc 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -11,142 +11,7 @@ namespace NifOgre { -void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) -{ - Ogre::Animation *anim = skel->createAnimation(name, stopTime); - - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *kfc = ctrls[i]; - if(kfc->data.empty()) - continue; - const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - - Ogre::Bone *bone = skel->getBone(targets[i]); - // NOTE: For some reason, Ogre doesn't like the node track ID being different from - // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? - anim->getNodeTrack(bone->getHandle()) : - anim->createNodeTrack(bone->getHandle(), bone); - - Ogre::Quaternion lastquat, curquat; - Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); - Ogre::Vector3 lastscale(1.0f), curscale(1.0f); - if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - - bool didlast = false; - while(!didlast) - { - float curtime = std::numeric_limits::max(); - - //Get latest time - if(quatiter != quatkeys.mKeys.end()) - curtime = std::min(curtime, quatiter->mTime); - if(traniter != trankeys.mKeys.end()) - curtime = std::min(curtime, traniter->mTime); - if(scaleiter != scalekeys.mKeys.end()) - curtime = std::min(curtime, scaleiter->mTime); - - curtime = std::max(curtime, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; - float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); - kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); - } - if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) - kframe->setTranslate(curtrans); - else - { - Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; - float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); - kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); - } - if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) - kframe->setScale(curscale); - else - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); -} - - -TextKeyMap NIFSkeletonLoader::extractTextKeys(const Nif::NiTextKeyExtraData *tk) -{ - TextKeyMap textkeys; - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - return textkeys; -} - -void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent) +void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent) { Ogre::Bone *bone; if(!skel->hasBone(node->name)) @@ -175,29 +40,16 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { - if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController || - ctrl->recType == Nif::RC_NiGeomMorpherController - )) + if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController || + ctrl->recType == Nif::RC_NiKeyframeController || + ctrl->recType == Nif::RC_NiGeomMorpherController + )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - textkeys = extractTextKeys(tk); - animroot = bone; - } - e = e->extra; - } - const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { @@ -205,7 +57,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); + buildBones(skel, children[i].getPtr(), bone); } } } @@ -218,68 +70,14 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); const Nif::Node *node = static_cast(nif->getRoot(0)); - std::vector ctrls; - Ogre::Bone *animroot = NULL; - TextKeyMap textkeys; try { - buildBones(skel, node, animroot, textkeys, ctrls); + buildBones(skel, node); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() < targets; - // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file - if(ctrls.size() == 0) // No animations? Then we're done. - return; - - float maxtime = 0.0f; - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *ctrl = ctrls[i]; - maxtime = std::max(maxtime, ctrl->timeStop); - Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); - if(target != NULL) - targets.push_back(target->name); - } - - if(targets.size() != ctrls.size()) - { - warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ - Ogre::StringConverter::toString(ctrls.size())+" controllers)"); - return; - } - - std::string currentgroup; - TextKeyMap::const_iterator keyiter = textkeys.begin(); - for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) - { - std::string::size_type sep = keyiter->second.find(':'); - if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || - (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) - continue; - currentgroup = keyiter->second.substr(0, sep); - - if(skel->hasAnimation(currentgroup)) - continue; - - TextKeyMap::const_iterator lastkeyiter = textkeys.end(); - while((--lastkeyiter)->first > keyiter->first) - { - if(lastkeyiter->second.find(':') == currentgroup.length() && - lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) - break; - } - - buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - } } diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp index e71dcfb15..38cfe14e3 100644 --- a/components/nifogre/skeleton.hpp +++ b/components/nifogre/skeleton.hpp @@ -36,8 +36,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader abort(); } - static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); + void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL); // Lookup to retrieve an Ogre bone handle for a given Nif record index std::map mNifToOgreHandleMap; @@ -46,7 +45,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader static LoaderMap sLoaders; public: - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void loadResource(Ogre::Resource *resource); static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); From 6f0b9a5f2cb98747715dbfa6c88b86f178c6f94c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 21:42:59 -0700 Subject: [PATCH 355/817] Avoid unnecessary multimap copies --- components/nifogre/ogrenifloader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e451326fe..57aa79403 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -676,9 +676,8 @@ class NIFObjectLoader } - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) + static void extractTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap &textkeys) { - TextKeyMap textkeys; for(size_t i = 0;i < tk->list.size();i++) { const std::string &str = tk->list[i].text; @@ -698,7 +697,6 @@ class NIFObjectLoader pos = nextpos; } } - return textkeys; } @@ -730,7 +728,7 @@ class NIFObjectLoader const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - objectlist.mTextKeys[trgtid] = extractTextKeys(tk); + extractTextKeys(tk, objectlist.mTextKeys[trgtid]); } else if(e->recType == Nif::RC_NiStringExtraData) { From 544011e0962b28b9cb978d90b9f1fe32455fb1ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 00:40:58 -0700 Subject: [PATCH 356/817] Fix 'start' text key fallback lookup --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cb54a0366..dc1312837 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -412,7 +412,7 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); while(startkey != keys.end() && startkey->second != tag) startkey++; - if(startkey == keys.end() && tag == "loop start") + if(startkey == keys.end() && start == "loop start") { tag = groupname+": start"; startkey = keys.begin(); From 26cc86ffdcd152b9acb6b953fff7de7acf2c48a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 00:42:45 -0700 Subject: [PATCH 357/817] Use the Nif node's transform for skinned fixups --- components/nifogre/mesh.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index 5637cd828..ca92f62d4 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -109,7 +109,6 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) { - Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); std::vector srcVerts = data->vertices; @@ -139,10 +138,6 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // explicitly attached later. mesh->setSkeletonName(mName); - // Get the skeleton resource, so vertices can be transformed into the bones' initial state. - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - skel = skelMgr->getByName(mName); - // Convert vertices and normals to bone space from bind position. It would be // better to transform the bones into bind position, but there doesn't seem to // be a reliable way to do that. @@ -153,11 +148,10 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape const Nif::NodeList &bones = skin->bones; for(size_t b = 0;b < bones.length();b++) { - Ogre::Bone *bone = skel->getBone(bones[b]->name); Ogre::Matrix4 mat; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bone->_getFullTransform() * mat; + mat = bones[b]->getWorldTransform() * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) @@ -310,6 +304,8 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Assign bone weights for this TriShape if(skin != NULL) { + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(mName); + const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++) From 9e05ee53da793846d0ddebd0b960aba621a621a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 01:18:08 -0700 Subject: [PATCH 358/817] Avoid looking for the controller if there is no NonAccum node Also, make sure there is a controller before updating the position. --- apps/openmw/mwrender/animation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index dc1312837..a2b429840 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -538,7 +538,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) + if(layeridx == 0 && mNonAccumRoot) { for(size_t i = 0;i < objlist.mControllers.size();i++) { @@ -601,14 +601,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(mLayer[layeridx].mNextKey->first > targetTime) { mLayer[layeridx].mTime = targetTime; - if(layeridx == 0 && mNonAccumRoot) + if(layeridx == 0 && mNonAccumCtrl) movement += updatePosition(); break; } NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); mLayer[layeridx].mTime = key->first; - if(layeridx == 0 && mNonAccumRoot) + if(layeridx == 0 && mNonAccumCtrl) movement += updatePosition(); mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); From 102b3bdef99d0d7ea1ee601565d3463a7cb5212d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 01:57:51 -0700 Subject: [PATCH 359/817] Update position by reference --- apps/openmw/mwrender/animation.cpp | 13 +++++++------ apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a2b429840..a8b2a1897 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -392,18 +392,19 @@ void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Og } -Ogre::Vector3 Animation::updatePosition() +void Animation::updatePosition(Ogre::Vector3 &position) { Ogre::Vector3 posdiff; - /* Get the non-accumulation root's difference from the last update. */ + /* Get the non-accumulation root's difference from the last update, and move the position + * accordingly. + */ posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; + position += posdiff; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; mAccumRoot->setPosition(-mLastPosition); - - return posdiff; } bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) @@ -602,14 +603,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) { mLayer[layeridx].mTime = targetTime; if(layeridx == 0 && mNonAccumCtrl) - movement += updatePosition(); + updatePosition(movement); break; } NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); mLayer[layeridx].mTime = key->first; if(layeridx == 0 && mNonAccumCtrl) - movement += updatePosition(); + updatePosition(movement); mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); timepassed = targetTime - mLayer[layeridx].mTime; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4860f44f5..a874cb1a8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -88,7 +88,7 @@ protected: /* Updates the position of the accum root node for the current time, and * returns the wanted movement vector from the previous update. */ - Ogre::Vector3 updatePosition(); + void updatePosition(Ogre::Vector3 &position); static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); From 68a9a4de5f77153f16e41fea47654b722fa6119d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:12:27 -0700 Subject: [PATCH 360/817] Fix setting and getting KeyframeController transforms --- components/nifogre/ogrenifloader.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 57aa79403..d36199f86 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -173,8 +173,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -193,8 +191,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -213,8 +209,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::QuaternionKeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -241,21 +235,21 @@ public: { if(mRotations.mKeys.size() > 0) return interpKey(mRotations.mKeys, time); - return Ogre::Quaternion(); + return mNode->getOrientation(); } virtual Ogre::Vector3 getTranslation(float time) const { if(mTranslations.mKeys.size() > 0) return interpKey(mTranslations.mKeys, time); - return Ogre::Vector3(0.0f); + return mNode->getPosition(); } virtual Ogre::Vector3 getScale(float time) const { if(mScales.mKeys.size() > 0) return Ogre::Vector3(interpKey(mScales.mKeys, time)); - return Ogre::Vector3(1.0f); + return mNode->getScale(); } virtual Ogre::Real getValue() const @@ -266,9 +260,12 @@ public: virtual void setValue(Ogre::Real time) { - mNode->setOrientation(Value::getRotation(time)); - mNode->setPosition(Value::getTranslation(time)); - mNode->setScale(Value::getScale(time)); + if(mRotations.mKeys.size() > 0) + mNode->setOrientation(interpKey(mRotations.mKeys, time)); + if(mTranslations.mKeys.size() > 0) + mNode->setPosition(interpKey(mTranslations.mKeys, time)); + if(mScales.mKeys.size() > 0) + mNode->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); } }; From 7241267d5c036f8c052598c18f04bdb8fef0b70e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:41:52 -0700 Subject: [PATCH 361/817] Make an AnimationValue for each animation layer --- apps/openmw/mwrender/animation.cpp | 8 +++--- apps/openmw/mwrender/animation.hpp | 40 ++++++++++++++++-------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a8b2a1897..3d938cc25 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -58,8 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) - , mPtr(ptr) + : mPtr(ptr) , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) @@ -71,6 +70,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + for(size_t i = 0;i < sMaxLayers;i++) + mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this, i)); + /* As long as we remain under 128 active controllers, we can avoid * reallocations. */ mActiveCtrls.reserve(128); @@ -153,7 +155,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b for(size_t i = 0;i < objlist.mControllers.size();i++) { if(objlist.mControllers[i].getSource().isNull()) - objlist.mControllers[i].setSource(mAnimationBaseValuePtr); + objlist.mControllers[i].setSource(mAnimationValuePtr[0]); } mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a874cb1a8..282cd3eca 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,10 +33,6 @@ protected: virtual Ogre::Real getValue() const; virtual void setValue(Ogre::Real value); }; - Ogre::SharedPtr > mAnimationBaseValuePtr; - - MWWorld::Ptr mPtr; - MWMechanics::CharacterController *mController; struct ObjectInfo { NifOgre::ObjectList mObjectList; @@ -47,20 +43,6 @@ protected: int mActiveLayers; }; - Ogre::SceneNode *mInsert; - Ogre::Entity *mSkelBase; - std::vector mObjects; - Ogre::Node *mAccumRoot; - Ogre::Bone *mNonAccumRoot; - Ogre::Vector3 mAccumulate; - Ogre::Vector3 mLastPosition; - - NifOgre::NodeTargetValue *mNonAccumCtrl; - float mAnimVelocity; - float mAnimSpeedMult; - std::vector > mActiveCtrls; - - static const size_t sMaxLayers = 1; struct AnimLayer { std::string mGroupName; std::vector > *mControllers; @@ -76,7 +58,27 @@ protected: bool mLooping; AnimLayer(); - } mLayer[sMaxLayers]; + }; + + MWWorld::Ptr mPtr; + MWMechanics::CharacterController *mController; + + Ogre::SceneNode *mInsert; + Ogre::Entity *mSkelBase; + std::vector mObjects; + Ogre::Node *mAccumRoot; + Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mAccumulate; + Ogre::Vector3 mLastPosition; + + NifOgre::NodeTargetValue *mNonAccumCtrl; + float mAnimVelocity; + float mAnimSpeedMult; + std::vector > mActiveCtrls; + + static const size_t sMaxLayers = 1; + AnimLayer mLayer[sMaxLayers]; + Ogre::SharedPtr > mAnimationValuePtr[sMaxLayers]; static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, From c58dfbe921cda569f950648f3307145a9c2cfe37 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:56:39 -0700 Subject: [PATCH 362/817] Specify the loop count to Animation::play --- apps/openmw/mwmechanics/character.cpp | 12 ++++++------ apps/openmw/mwrender/animation.cpp | 19 ++++++++++++------- apps/openmw/mwrender/animation.hpp | 6 +++--- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 07f7b6940..664ed7c03 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } CharacterController::CharacterController(const CharacterController &rhs) @@ -155,7 +155,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", 0); } return; } @@ -164,7 +164,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", 0); } else if(mAnimQueue.size() > 0) { @@ -172,7 +172,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", "stop", false); + mAnimation->play(mCurrentGroup, "start", "stop", 0); } } return; @@ -284,7 +284,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", false); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0); } else if(mode == 0) { @@ -316,7 +316,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3d938cc25..4e82f0b8c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,7 +23,7 @@ Animation::AnimLayer::AnimLayer() , mTextKeys(NULL) , mTime(0.0f) , mPlaying(false) - , mLooping(false) + , mLoopCount(0) { } @@ -449,14 +449,20 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: return true; } -void Animation::doLoop(size_t layeridx) +bool Animation::doLoop(size_t layeridx) { + if(mLayer[layeridx].mLoopCount == 0) + return false; + mLayer[layeridx].mLoopCount--; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; mLayer[layeridx].mNextKey++; mLayer[layeridx].mPlaying = true; if(layeridx == 0 && mNonAccumCtrl) mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; + + return true; } @@ -495,9 +501,8 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLayer[layeridx].mLooping) + if(doLoop(layeridx)) { - doLoop(layeridx); if(mLayer[layeridx].mTime >= time) return false; return true; @@ -510,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -527,7 +532,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName.clear(); mLayer[layeridx].mTextKeys = NULL; mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; + mLayer[layeridx].mLoopCount = 0; mLayer[layeridx].mPlaying = false; foundanim = true; @@ -562,7 +567,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mLoopCount = loops; mLayer[layeridx].mPlaying = true; if(layeridx == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 282cd3eca..1b300887f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,7 +55,7 @@ protected: float mTime; bool mPlaying; - bool mLooping; + size_t mLoopCount; AnimLayer(); }; @@ -101,7 +101,7 @@ protected: */ bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(size_t layeridx); + bool doLoop(size_t layeridx); bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); @@ -129,7 +129,7 @@ public: void setSpeed(float speed); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); + void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); Ogre::Node *getNode(const std::string &name); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 41770d489..c22d8a4da 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -155,7 +155,7 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", false); + mAnimation->play("inventoryhandtohand", "start", "stop", 0); } // -------------------------------------------------------------------------------------------------- @@ -189,7 +189,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", false); + mAnimation->play("idle", "start", "stop", 0); updateCamera(); } From b482d5be097b16a8df8ecc04c8b25252e81e746c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 05:23:45 -0700 Subject: [PATCH 363/817] Add a method to check if a given layer is playing --- apps/openmw/mwrender/animation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1b300887f..87c57ebf7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -132,6 +132,9 @@ public: void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); + bool isPlaying(size_t layeridx) const + { return mLayer[layeridx].mPlaying; } + Ogre::Node *getNode(const std::string &name); }; From e8cabc94349d95bbb9e23a3604e8d1afe85ed8b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 06:32:11 -0700 Subject: [PATCH 364/817] Pass the loop count from loopgroup to the play method Instead of queueing each iteration separately. --- apps/openmw/mwmechanics/character.cpp | 34 +++++++-------------------- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 11 ++++++++- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 664ed7c03..086a2fc25 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -150,29 +150,16 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::markerEvent(float time, const std::string &evt) { - if(evt == "loop stop") - { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", 0); - } - return; - } if(evt == "stop") { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", 0); - } - else if(mAnimQueue.size() > 0) + if(mAnimQueue.size() > 0) { mAnimQueue.pop_front(); if(mAnimQueue.size() > 0) { - mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", "stop", 0); + mCurrentGroup = mAnimQueue.front().first; + size_t count = mAnimQueue.front().second; + mAnimation->play(mCurrentGroup, "start", "stop", count); } } return; @@ -223,7 +210,6 @@ void CharacterController::update(float duration, Movement &movement) if(vec.x > 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight) : (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight)), true); - else if(vec.x < 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); @@ -236,10 +222,10 @@ void CharacterController::update(float duration, Movement &movement) if(vec.y > 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward) : (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward)), true); - else if(vec.y < 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true); + // Apply any sideways movement manually movement.mPosition[0] += vec.x * (speed*duration); } @@ -250,7 +236,7 @@ void CharacterController::update(float duration, Movement &movement) else if(rot.z < 0.0f) setState(CharState_TurnLeft, true); } - else if(mAnimQueue.size() == 0) + else if(getState() != CharState_SpecialIdle || !mAnimation->isPlaying(0)) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); movement.mRotation[0] += rot.x * duration; @@ -280,17 +266,15 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int if(mode != 0 || mAnimQueue.size() == 0) { mAnimQueue.clear(); - while(count-- > 0) - mAnimQueue.push_back(groupname); + mAnimQueue.push_back(std::make_pair(groupname, count-1)); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); } else if(mode == 0) { mAnimQueue.resize(1); - while(count-- > 0) - mAnimQueue.push_back(groupname); + mAnimQueue.push_back(std::make_pair(groupname, count-1)); } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 5b5a65f79..4453b078d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -72,7 +72,7 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - typedef std::deque AnimationQueue; + typedef std::deque > AnimationQueue; AnimationQueue mAnimQueue; std::string mCurrentGroup; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4e82f0b8c..b205d9519 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -499,7 +499,16 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ return true; } - if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) + if(evt.compare(off, len, "loop stop") == 0) + { + if(doLoop(layeridx)) + { + if(mLayer[layeridx].mTime >= time) + return false; + } + return true; + } + if(evt.compare(off, len, "stop") == 0) { if(doLoop(layeridx)) { From b80891099e0171af7a58dd9733b4abfd901fc3aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 06:48:34 -0700 Subject: [PATCH 365/817] Don't use the character controller to handle text keys The Animation class has the Ptr and can call to whatever subsystem is needed. --- apps/openmw/mwmechanics/character.cpp | 38 +++++++++------------------ apps/openmw/mwmechanics/character.hpp | 6 ----- apps/openmw/mwrender/animation.cpp | 16 +++-------- 3 files changed, 16 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 086a2fc25..bbf679cda 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -148,27 +148,6 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) } -void CharacterController::markerEvent(float time, const std::string &evt) -{ - if(evt == "stop") - { - if(mAnimQueue.size() > 0) - { - mAnimQueue.pop_front(); - if(mAnimQueue.size() > 0) - { - mCurrentGroup = mAnimQueue.front().first; - size_t count = mAnimQueue.front().second; - mAnimation->play(mCurrentGroup, "start", "stop", count); - } - } - return; - } - - std::cerr<< "Unhandled animation event: "<isPlaying(0)) - setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + { + if(mAnimQueue.size() > 0) + { + mCurrentGroup = mAnimQueue.front().first; + size_t count = mAnimQueue.front().second; + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "start", "stop", count); + } + else + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + } movement.mRotation[0] += rot.x * duration; movement.mRotation[1] += rot.y * duration; @@ -263,17 +252,16 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int else { count = std::max(count, 1); - if(mode != 0 || mAnimQueue.size() == 0) + if(mode != 0 || getState() != CharState_SpecialIdle) { mAnimQueue.clear(); - mAnimQueue.push_back(std::make_pair(groupname, count-1)); mCurrentGroup = groupname; mState = CharState_SpecialIdle; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); } else if(mode == 0) { - mAnimQueue.resize(1); + mAnimQueue.clear(); mAnimQueue.push_back(std::make_pair(groupname, count-1)); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4453b078d..4bbea1551 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,12 +79,6 @@ class CharacterController CharacterState mState; bool mSkipAnim; -protected: - /* Called by the animation whenever a new text key is reached. */ - void markerEvent(float time, const std::string &evt); - - friend class MWRender::Animation; - public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b205d9519..c0fee0d3b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -499,7 +499,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ return true; } - if(evt.compare(off, len, "loop stop") == 0) + if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { if(doLoop(layeridx)) { @@ -508,18 +508,8 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } return true; } - if(evt.compare(off, len, "stop") == 0) - { - if(doLoop(layeridx)) - { - if(mLayer[layeridx].mTime >= time) - return false; - return true; - } - // fall-through - } - if(mController) - mController->markerEvent(time, evt.substr(off)); + + std::cerr<< "Unhandled animation textkey: "< Date: Wed, 24 Apr 2013 07:10:41 -0700 Subject: [PATCH 366/817] Remove the character controller from the Animation class --- apps/openmw/mwmechanics/character.cpp | 13 ------------- apps/openmw/mwmechanics/character.hpp | 1 - apps/openmw/mwrender/animation.cpp | 9 +-------- apps/openmw/mwrender/animation.hpp | 12 +++--------- 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bbf679cda..2a7ab8b09 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -108,8 +108,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; - mAnimation->setController(this); - getStateInfo(mState, &mCurrentGroup); if(MWWorld::Class::get(mPtr).isActor()) { @@ -126,17 +124,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } -CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) - , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) - , mSkipAnim(rhs.mSkipAnim) -{ - if(!mAnimation) - return; - /* We've been copied. Update the animation with the new controller. */ - mAnimation->setController(this); -} - CharacterController::~CharacterController() { } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4bbea1551..ffd220ff2 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -81,7 +81,6 @@ class CharacterController public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); - CharacterController(const CharacterController &rhs); virtual ~CharacterController(); void updatePtr(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0fee0d3b..c2f453516 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -59,14 +59,13 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) - , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mNonAccumCtrl(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { @@ -299,12 +298,6 @@ bool Animation::hasAnimation(const std::string &anim) } -void Animation::setController(MWMechanics::CharacterController *controller) -{ - mController = controller; -} - - void Animation::setAccumulation(const Ogre::Vector3 &accum) { mAccumulate = accum; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 87c57ebf7..526bca69a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -8,10 +8,6 @@ #include "../mwworld/ptr.hpp" -namespace MWMechanics -{ - class CharacterController; -} namespace MWRender { @@ -61,20 +57,20 @@ protected: }; MWWorld::Ptr mPtr; - MWMechanics::CharacterController *mController; Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; std::vector mObjects; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; + NifOgre::NodeTargetValue *mNonAccumCtrl; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - NifOgre::NodeTargetValue *mNonAccumCtrl; + std::vector > mActiveCtrls; + float mAnimVelocity; float mAnimSpeedMult; - std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; AnimLayer mLayer[sMaxLayers]; @@ -116,8 +112,6 @@ public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); - void setController(MWMechanics::CharacterController *controller); - void updatePtr(const MWWorld::Ptr &ptr); bool hasAnimation(const std::string &anim); From 53fb17da10436022178562d5d573659f769e0102 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 24 Apr 2013 21:42:04 +0200 Subject: [PATCH 367/817] Rotation system fixes --- apps/openmw/mwscript/transformationextensions.cpp | 9 +++------ apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index beb6c3d8c..f2179897d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -153,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -563,17 +563,14 @@ namespace MWScript if (axis == "x") { - ptr.getRefData().getLocalRotation().rot[0]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { - ptr.getRefData().getLocalRotation().rot[1]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { - ptr.getRefData().getLocalRotation().rot[2]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 69bcad619..aa9107c6e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -827,6 +827,14 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) { if (ptr.getRefData().getBaseNode() != 0) { + + if(axis==Ogre::Vector3::UNIT_X) + ptr.getRefData().getLocalRotation().rot[0]+=rotation; + else if(axis==Ogre::Vector3::UNIT_Y) + ptr.getRefData().getLocalRotation().rot[1]+=rotation; + else if(axis==Ogre::Vector3::UNIT_Z) + ptr.getRefData().getLocalRotation().rot[2]+=rotation; + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); mPhysics->rotateObject(ptr); } From c0102954f1d435b21aa2e6a7f1b6d61207ac925b Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 30 Mar 2013 13:28:17 +0100 Subject: [PATCH 368/817] Add non-breaking space to font code range --- files/mygui/openmw_font.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index b1446fae1..f1be51e16 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -9,6 +9,7 @@ + From cd57e3f896260e480db9fab1aa0d0b9e03f2aa09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 23:51:43 +0200 Subject: [PATCH 369/817] Auto calculate attributes if there are not specified in the NPC record --- apps/openmw/mwclass/npc.cpp | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7cda87bb1..ea49ae4a4 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,67 @@ namespace { return new CustomData (*this); } + + void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) + { + // race bonus + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mRace); + + bool male = (npc->mFlags & ESM::NPC::Female) == 0; + + int level = creatureStats.getLevel(); + + for (int i=0; imData.mAttributeValues[i]; + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); + } + + // class bonus + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mClass); + + for (int i=0; i<2; ++i) + { + int attribute = class_->mData.mAttribute[i]; + if (attribute>=0 && attribute<8) + { + creatureStats.getAttribute(attribute).setBase ( + creatureStats.getAttribute(attribute).getBase() + 10); + } + } + + // skill bonus + for (int attribute=0; attributegetStore().get().find(j); + + if (skill->mData.mAttribute != attribute) + continue; + + // is this a minor or major skill? + float add=0.2; + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][0] == j) + add=0.5; + } + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][1] == j) + add=1.0; + } + modifierSum += add; + } + creatureStats.getAttribute(attribute).setBase ( std::min(creatureStats.getAttribute(attribute).getBase() + + static_cast((level-1) * modifierSum+0.5), 100) ); + } + } } namespace MWClass @@ -126,15 +187,14 @@ namespace MWClass } else { - for (int i=0; i<8; ++i) - data->mCreatureStats.getAttribute (i).set (10); - for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + + autoCalculateAttributes(ref->mBase, data->mCreatureStats); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 2c8b0a154175f3320fe4e082a5208d538f707875 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 00:26:36 +0200 Subject: [PATCH 370/817] last minute change to changelog --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 5f3845776..d5a5dcc18 100644 --- a/readme.txt +++ b/readme.txt @@ -136,6 +136,7 @@ Bug #700: "On the rocks" mod does not load its UV coordinates correctly. Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon +Bug #725: Auto calculate stats Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From 21bdcc9f20d14e7d5aabf906860cee573e0e31a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 01:33:04 +0200 Subject: [PATCH 371/817] Only use the shader based mygui manager if the fixed pipeline is unavailable --- libs/openengine/gui/manager.cpp | 30 ++++++++++++++++++++++++++---- libs/openengine/gui/manager.hpp | 5 +++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index f9117586f..a0a4ab0ae 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -559,6 +559,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool assert(mgr); mSceneMgr = mgr; + mShaderRenderManager = NULL; + mRenderManager = NULL; using namespace MyGUI; @@ -574,7 +576,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new MyGUI::ShaderBasedRenderManager(); + if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) + mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); + else + mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); @@ -582,7 +587,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool if (!theLogFile.empty()) LogManager::getInstance().createDefaultSource(theLogFile); - mRenderManager->initialise(wnd, mgr); + if (mShaderRenderManager) + mShaderRenderManager->initialise(wnd, mgr); + else + mRenderManager->initialise(wnd, mgr); mDataManager->initialise("General"); // Create GUI @@ -592,8 +600,16 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) { - mRenderManager->setRenderWindow (wnd); - mRenderManager->setActiveViewport(0); + if (mShaderRenderManager) + { + mShaderRenderManager->setRenderWindow (wnd); + mShaderRenderManager->setActiveViewport(0); + } + else + { + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); + } } void MyGUIManager::shutdown() @@ -606,6 +622,12 @@ void MyGUIManager::shutdown() delete mRenderManager; mRenderManager = NULL; } + if(mShaderRenderManager) + { + mShaderRenderManager->shutdown(); + delete mShaderRenderManager; + mShaderRenderManager = NULL; + } if(mDataManager) { mDataManager->shutdown(); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index eec867ff8..9535f2a24 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,6 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; + class OgreRenderManager; class ShaderBasedRenderManager; } @@ -25,12 +26,12 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::ShaderBasedRenderManager* mRenderManager; + MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mShaderRenderManager; Ogre::SceneManager* mSceneMgr; public: - MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL), mGui(NULL) {} MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) { setup(wnd,mgr,logging, logDir); From 87ce2110dcc912394a6d49599a7bb7558bac68a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 14:41:26 +0200 Subject: [PATCH 372/817] hotfix for CharacterPreview destructor --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8396acaea..41770d489 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -21,13 +21,15 @@ namespace MWRender CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mSizeX(sizeX) - , mSizeY(sizeY) - , mName(name) + + : mSceneMgr (0) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) + , mName(name) + , mSizeX(sizeX) + , mSizeY(sizeY) { } @@ -88,16 +90,20 @@ namespace MWRender CharacterPreview::~CharacterPreview () { - //Ogre::TextureManager::getSingleton().remove(mName); - mSceneMgr->destroyCamera (mName); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneMgr) + { + //Ogre::TextureManager::getSingleton().remove(mName); + mSceneMgr->destroyAllCameras(); + delete mAnimation; + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + } } void CharacterPreview::rebuild() { assert(mAnimation); delete mAnimation; + mAnimation = 0; mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); From 51580ead4f9c20f8b683384c618c5f1b25c2afd7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 17:57:22 +0200 Subject: [PATCH 373/817] Fix consecutive dialogue choices --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 9380ab76c..220adf566 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -426,6 +426,7 @@ namespace MWDialogue void DialogueManager::questionAnswered (const std::string& answer) { + if (mChoiceMap.find(answer) != mChoiceMap.end()) { mChoice = mChoiceMap[answer]; @@ -442,6 +443,10 @@ namespace MWDialogue std::string text = info->mResponse; parseText (text); + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); @@ -449,9 +454,6 @@ namespace MWDialogue mLastDialogue = *info; } } - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; } updateTopics(); From 2dc01fe56b923c382ebfe7da5c1829d8580bb450 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 21 Apr 2013 11:41:09 -0700 Subject: [PATCH 374/817] fixed the type of iterator uses in MWWorld::Store The containers type used to declare some iterators was not an exact match for the type of the container the iterator was being initialized from. This was causing build failure on windows. --- apps/openmw/mwworld/store.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 959b944e1..7949cbe00 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -475,7 +475,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -493,7 +493,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -534,7 +534,7 @@ namespace MWWorld void setUp() { //typedef std::vector::iterator Iterator; - typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef DynamicExt::iterator ExtIterator; typedef std::map::iterator IntIterator; //std::sort(mInt.begin(), mInt.end(), RecordCmp()); From a7092ef2d709a575848451ade18e45e360f80f09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Apr 2013 21:24:48 +0200 Subject: [PATCH 375/817] Fix activation not working sometimes The current player cell was only being updated when the reference was not empty, causing it to incorrectly detect a cell change the first time something was activated in a newly visited cell, immediately closing the opened dialogue again. --- apps/openmw/mwgui/referenceinterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 66e036d92..86a85be18 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -18,17 +18,17 @@ namespace MWGui void ReferenceInterface::checkReferenceAvailable() { - if (mPtr.isEmpty()) - return; - MWWorld::Ptr::CellStore* playerCell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) - || mPtr.getRefData().getCount() == 0) + || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) { - mPtr = MWWorld::Ptr(); - onReferenceUnavailable(); + if (!mPtr.isEmpty()) + { + mPtr = MWWorld::Ptr(); + onReferenceUnavailable(); + } } mCurrentPlayerCell = playerCell; From baa7a9160c35b4ce13dde8666a2039eb998354e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Apr 2013 07:57:53 +0200 Subject: [PATCH 376/817] Rank condition should always fail if NPC is not in a faction --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 78969ffd0..52c7bd4f3 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -73,6 +73,11 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (iter->second < info.mData.mRank) return false; } + else if (info.mData.mRank != -1) + { + // if there is a rank condition, but the NPC is not in a faction, always fail + return false; + } // Gender if (!isCreature) From 8d0e5fc0c4b7272508309e4325ab6c5590b2aa8b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 22 Apr 2013 09:56:11 +0200 Subject: [PATCH 377/817] updated changelog once more --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index d5a5dcc18..c033f9547 100644 --- a/readme.txt +++ b/readme.txt @@ -137,6 +137,8 @@ Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon Bug #725: Auto calculate stats +Bug #728: Failure to open container and talk dialogue +Bug #731: Crash with Mush-Mere's "background" topic Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From ad05f238deaec2679336e7d0c35366b53cdfa4c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Apr 2013 22:47:21 +0200 Subject: [PATCH 378/817] Use one vertex buffer for all UV coordinates --- components/nifogre/mesh.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c3..6d940deed 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -260,13 +260,24 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Texture UV coordinates size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) + if (numUVs) { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + + for(size_t i = 0; i < numUVs; i++) + decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + + vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + + std::vector allUVs; + allUVs.reserve(srcVerts.size()*numUVs); + for (size_t vert = 0; vertuvlist[i][vert]); + + vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); bind->setBinding(nextBuf++, vbuf); } From 933f89414842eaa566803bb6ed506e85380fd2e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Apr 2013 02:31:51 +0200 Subject: [PATCH 379/817] Added Blind and Night Eye effects --- apps/openmw/mwrender/renderingmanager.cpp | 27 ++++++++++++++++------- libs/openengine/ogre/fader.cpp | 12 +++++----- libs/openengine/ogre/fader.hpp | 4 ++++ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 029cf394b..da51f10c1 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -30,6 +30,8 @@ #include "../mwbase/inputmanager.hpp" // FIXME #include "../mwbase/windowmanager.hpp" // FIXME +#include "../mwmechanics/creaturestats.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/player.hpp" @@ -315,13 +317,15 @@ void RenderingManager::update (float duration, bool paused) { MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; + mRendering.getFader()->setFactor(1.f-(blind / 100.f)); + + setAmbientMode(); + // player position - MWWorld::RefData &data = - MWBase::Environment::get() - .getWorld() - ->getPlayer() - .getPlayer() - .getRefData(); + MWWorld::RefData &data = player.getRefData(); float *_playerPos = data.getPosition().pos; Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); @@ -597,8 +601,15 @@ void RenderingManager::setSunColour(const Ogre::ColourValue& colour) void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) { - mRendering.getScene()->setAmbientLight(colour); - mTerrainManager->setAmbient(colour); + mAmbientColor = colour; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int nightEye = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::NightEye)).mMagnitude; + Ogre::ColourValue final = colour; + final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); + + mRendering.getScene()->setAmbientLight(final); + mTerrainManager->setAmbient(final); } void RenderingManager::sunEnable(bool real) diff --git a/libs/openengine/ogre/fader.cpp b/libs/openengine/ogre/fader.cpp index 9390d0664..923b0b7e3 100644 --- a/libs/openengine/ogre/fader.cpp +++ b/libs/openengine/ogre/fader.cpp @@ -19,6 +19,7 @@ Fader::Fader(Ogre::SceneManager* sceneMgr) , mTargetAlpha(0.f) , mCurrentAlpha(0.f) , mStartAlpha(0.f) + , mFactor(1.f) { // Create the fading material MaterialPtr material = MaterialManager::getSingleton().create("FadeInOutMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); @@ -62,19 +63,20 @@ void Fader::update(float dt) mCurrentAlpha += dt/mTargetTime * (mTargetAlpha-mStartAlpha); if (mCurrentAlpha > mTargetAlpha) mCurrentAlpha = mTargetAlpha; } - - applyAlpha(); - + mRemainingTime -= dt; } - if (mCurrentAlpha == 0.f) mRectangle->setVisible(false); + if (1.f-((1.f-mCurrentAlpha) * mFactor) == 0.f) + mRectangle->setVisible(false); + else + applyAlpha(); } void Fader::applyAlpha() { mRectangle->setVisible(true); - mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, mCurrentAlpha); + mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 1.f-((1.f-mCurrentAlpha) * mFactor)); } void Fader::fadeIn(float time) diff --git a/libs/openengine/ogre/fader.hpp b/libs/openengine/ogre/fader.hpp index bddf5dc91..53124e2f6 100644 --- a/libs/openengine/ogre/fader.hpp +++ b/libs/openengine/ogre/fader.hpp @@ -29,6 +29,8 @@ namespace Render void fadeOut(const float time); void fadeTo(const int percent, const float time); + void setFactor (float factor) { mFactor = factor; } + private: enum FadingMode { @@ -49,6 +51,8 @@ namespace Render float mCurrentAlpha; float mStartAlpha; + float mFactor; + Ogre::SceneManager* mSceneMgr; }; }} From 0817d59f23d4b2f36711109696c87cf6c22ad672 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 19:09:36 -0700 Subject: [PATCH 380/817] Allow specifying where to start in an animation --- apps/openmw/mwmechanics/character.cpp | 14 +++++++------- apps/openmw/mwrender/animation.cpp | 18 +++++++++++++----- apps/openmw/mwrender/animation.hpp | 18 ++++++++++++++++-- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2a7ab8b09..9397b2e35 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -121,7 +121,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); + mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); } CharacterController::~CharacterController() @@ -204,15 +204,15 @@ void CharacterController::update(float duration, Movement &movement) } else if(getState() != CharState_SpecialIdle || !mAnimation->isPlaying(0)) { - if(mAnimQueue.size() > 0) + if(mAnimQueue.size() == 0) + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + else { mCurrentGroup = mAnimQueue.front().first; size_t count = mAnimQueue.front().second; mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "start", "stop", count); + mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); } - else - setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); } movement.mRotation[0] += rot.x * duration; @@ -244,7 +244,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) { @@ -275,7 +275,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); + mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2f453516..0f509d276 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -402,7 +402,7 @@ void Animation::updatePosition(Ogre::Vector3 &position) mAccumRoot->setPosition(-mLastPosition); } -bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -432,9 +432,17 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: mLayer[layeridx].mLoopStartKey = startkey; mLayer[layeridx].mStopKey = stopkey; mLayer[layeridx].mNextKey = startkey; - mLayer[layeridx].mNextKey++; - mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first + ((mLayer[layeridx].mStopKey->first- + mLayer[layeridx].mStartKey->first) * startpoint); + + tag = groupname+": loop start"; + while(mLayer[layeridx].mNextKey->first <= mLayer[layeridx].mTime && mLayer[layeridx].mNextKey != mLayer[layeridx].mStopKey) + { + if(mLayer[layeridx].mNextKey->second == tag) + mLayer[layeridx].mLoopStartKey = mLayer[layeridx].mNextKey; + mLayer[layeridx].mNextKey++; + } if(layeridx == 0 && nonaccumctrl) mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; @@ -507,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -554,7 +562,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!foundanim) { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop, startpoint)) continue; mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 526bca69a..d7f38545f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -95,7 +95,10 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, + NifOgre::NodeTargetValue *nonaccumctrl, + const std::string &groupname, const std::string &start, const std::string &stop, + float startpoint); bool doLoop(size_t layeridx); @@ -123,7 +126,18 @@ public: void setSpeed(float speed); - void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); + /** Plays an animation. + * \param groupname Name of the animation group to play. + * \param start Key marker from which to start. + * \param stop Key marker to stop at. + * \param startpoint How far in between the two markers to start. 0 starts + * at the start marker, 1 starts at the stop marker. + * \param loops How many times to loop the animation. This will use the + * "loop start" and "loop stop" markers if they exist, + * otherwise it will use "start" and "stop". + */ + void play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); + virtual Ogre::Vector3 runAnimation(float timepassed); bool isPlaying(size_t layeridx) const diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index c22d8a4da..24b089db3 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -155,7 +155,7 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", 0); + mAnimation->play("inventoryhandtohand", "start", "stop", 0.0f, 0); } // -------------------------------------------------------------------------------------------------- @@ -189,7 +189,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", 0); + mAnimation->play("idle", "start", "stop", 0.0f, 0); updateCamera(); } From 9e3917881d5d4f0b1c23c31d879369a06a9bc4bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Apr 2013 04:44:30 +0200 Subject: [PATCH 381/817] Don't fail on nonexistent items in a levelled list --- apps/openmw/mwworld/containerstore.cpp | 85 ++++++++++++++------------ 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 05026a98b..5cf534239 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -193,59 +193,68 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + try { - const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - const std::vector& items = levItem->mList; + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); - - failChance += levItem->mChanceNone; - - if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { - for (int i=0; i()->mBase; + const std::vector& items = levItem->mList; - float random = static_cast (std::rand()) / RAND_MAX; - if (random >= failChance/100.f) - { - std::vector candidates; - int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); + + failChance += levItem->mChanceNone; + + if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { - if (it->mLevel > highestLevel) - highestLevel = it->mLevel; + for (int i=0; i highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + float random = static_cast (std::rand()) / RAND_MAX; + if (random >= failChance/100.f) { - if (playerLevel >= it->mLevel - && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + std::vector candidates; + int highestLevel = 0; + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { - candidates.push_back(it->mId); - if (it->mLevel >= highest.first) - highest = std::make_pair(it->mLevel, it->mId); + if (it->mLevel > highestLevel) + highestLevel = it->mLevel; } + std::pair highest = std::make_pair(-1, ""); + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (playerLevel >= it->mLevel + && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + { + candidates.push_back(it->mId); + if (it->mLevel >= highest.first) + highest = std::make_pair(it->mLevel, it->mId); + } + + } + if (!candidates.size()) + return; + std::string item = candidates[std::rand()%candidates.size()]; + addInitialItem(item, owner, count, failChance, false); } - if (!candidates.size()) - return; - std::string item = candidates[std::rand()%candidates.size()]; - addInitialItem(item, owner, count, failChance, false); + } + else + { + ref.getPtr().getRefData().setCount (count); + ref.getPtr().getCellRef().mOwner = owner; + addImp (ref.getPtr()); } } - else + catch (std::logic_error& e) { - ref.getPtr().getRefData().setCount (count); - ref.getPtr().getCellRef().mOwner = owner; - addImp (ref.getPtr()); + // Vanilla doesn't fail on nonexistent items in levelled lists + std::cerr << "Warning: ignoring nonexistent item '" << id << "'" << std::endl; + return; } } From 03ee7663a3e89698c36108d03a7fcd036762d827 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 17:33:28 -0800 Subject: [PATCH 382/817] reworked NIFStream to use a type-handler Reworked NIFStream to use a type-handler system to decide how to extract data from the NIF. It also has the capability to perform bulk reads on compatible platforms, thus improving cell-load performance. --- components/nif/nifstream.hpp | 338 +++++++++++++++++++++++------------ 1 file changed, 225 insertions(+), 113 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index a2595d17b..7abfae9e8 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP +#include + namespace Nif { @@ -11,168 +13,278 @@ class NIFStream { /// Input stream Ogre::DataStreamPtr inp; - uint8_t read_byte() + template + value_t read_le () { - uint8_t byte; - if(inp->read(&byte, 1) != 1) return 0; - return byte; - } - uint16_t read_le16() - { - uint8_t buffer[2]; - if(inp->read(buffer, 2) != 2) return 0; - return buffer[0] | (buffer[1]<<8); - } - uint32_t read_le32() - { - uint8_t buffer[4]; - if(inp->read(buffer, 4) != 4) return 0; - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); - } - float read_le32f() - { - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; + uint8_t buffer [sizeof (value_t)]; + + if (inp->read (buffer, sizeof (buffer)) != sizeof (buffer)) + throw std::runtime_error ("unexpected"); + + value_t Value = 0; + value_t Shift = 0; + + for (size_t i = 0; i < sizeof (value_t); ++i) + { + Value |= value_t (buffer[i]) << Shift; + Shift += 8; + } + + return Value; } public: + /* + * This should be true for any processor/platform whose endianess, alignment + * and packing rules would be compatible with x86 and not fault or degrade + * with misaligned reads. This enables some pretty big savings when reading in + * animations and meshes. + */ +#if defined (__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) + static const bool FileCompatiblePlatform = true; +#else + static const bool FileCompatiblePlatform = false; +#endif + + template + struct handler; + + template + struct le_handler; + + template + friend struct le_handler; + + template + struct conversion_handler; + NIFFile * const file; - NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + NIFStream (NIFFile * file, Ogre::DataStreamPtr inp) : file (file), inp (inp) {} /************************************************* Parser functions ****************************************************/ - template - struct GetHandler - { - typedef T (NIFStream::*fn_t)(); - - static const fn_t sValue; // this is specialized per supported type in the .cpp file - - static T read (NIFStream* nif) - { - return (nif->*sValue) (); - } - }; + void skip(size_t size) { return inp->skip (size); } + size_t read (void * data, size_t size) { return inp->read (data, size); } template - void read (NIFStream* nif, T & Value) + void uncheckedRead (T & Value) { - Value = GetHandler ::read (nif); + typedef handler handler_t; + handler_t::extract (*this, Value); } - void skip(size_t size) { inp->skip(size); } - void read (void * data, size_t size) { inp->read (data, size); } + template + T getValue () + { + T Value; + getValue (Value); + return Value; + } - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - int getUInt() { return read_le32(); } - float getFloat() { return read_le32f(); } - Ogre::Vector2 getVector2() + template + void getValue (T & Value) { - float a[2]; - for(size_t i = 0;i < 2;i++) - a[i] = getFloat(); - return Ogre::Vector2(a); - } - Ogre::Vector3 getVector3() - { - float a[3]; - for(size_t i = 0;i < 3;i++) - a[i] = getFloat(); - return Ogre::Vector3(a); - } - Ogre::Vector4 getVector4() - { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Vector4(a); - } - Ogre::Matrix3 getMatrix3() - { - Ogre::Real a[3][3]; - for(size_t i = 0;i < 3;i++) + typedef handler handler_t; + if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) { - for(size_t j = 0;j < 3;j++) - a[i][j] = Ogre::Real(getFloat()); + BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); + BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (T), "unexpected structure size"); + + inp->read (&Value, handler_t::EncodedLength); + } + else + { + handler_t::extract (*this, Value); } - return Ogre::Matrix3(a); } - Ogre::Quaternion getQuaternion() + + template + void getArray (element_type * Array, size_t Size) { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Quaternion(a); + typedef handler handler_t; + + if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) + { + BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); + BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (element_type), "unexpected structure size"); + + inp->read (Array, handler_t::EncodedLength * Size); + } + else + { + for(size_t i = 0; i < Size; i++) + handler_t::extract (*this, Array[i]); + } } - Transformation getTrafo() + + template + void getStdVector (std::vector & Vector, size_t Size) { - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; + Vector.resize(Size); + + getArray (&Vector.front (), Vector.size ()); } + template + void getStdVector (std::vector & Vector) + { + length_type Length; + + getValue (Length); + + getStdVector (Vector, Length); + } + + char getChar() { return getValue (); } + signed int getInt() { return getValue (); } + unsigned int getUInt() { return getValue (); } + signed short getShort() { return getValue (); } + unsigned short getUShort() { return getValue (); } + //signed long getLong() { return getValue (); } + //unsigned long getULong() { return getValue (); } + float getFloat() { return getValue (); } + + Ogre::Vector2 getVector2() { return getValue (); } + Ogre::Vector3 getVector3() { return getValue (); } + Ogre::Vector4 getVector4() { return getValue (); } + Ogre::Matrix3 getMatrix3() { return getValue (); } + Ogre::Quaternion getQuaternion() { return getValue (); } + + Transformation getTrafo() { return getValue (); } + + void getShorts(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getFloats(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector2s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector3s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector4s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getQuaternions(std::vector &vec, size_t size) { return getStdVector (vec, size); } + std::string getString(size_t length) { std::vector str (length+1, 0); - if(inp->read(&str[0], length) != length) + if(read(&str[0], length) != length) throw std::runtime_error ("string length in NIF file does not match"); return &str[0]; } std::string getString() { - size_t size = read_le32(); + size_t size = getValue (); return getString(size); } +}; - void getShorts(std::vector &vec, size_t size) +/* + * generic type handlers + */ + +template +struct NIFStream::handler < type [Size] > +{ + typedef handler inner_handler; + + static const bool FixedLength = inner_handler::FixedLength; + static const size_t EncodedLength = inner_handler::EncodedLength * Size; + static const bool FileCompatibleLayout = inner_handler::FileCompatibleLayout; + + static void extract (NIFStream & Stream, type (&Value) [Size]) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); + for (size_t i = 0; i < Size; ++i) + inner_handler::extract (Stream, Value [i]); } - void getFloats(std::vector &vec, size_t size) +}; + +template +struct NIFStream::le_handler +{ + static const bool FixedLength = true; + static const size_t EncodedLength = sizeof (backing_type); + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream & Stream, presentation_type & Value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); + BOOST_STATIC_ASSERT_MSG(sizeof (presentation_type) == sizeof (backing_type), "Invalid use of NIFile::le_handler template"); + + union { + + backing_type Backing; + presentation_type Presentation; + + } u; + + u.Backing = Stream.read_le (); + + Value = u.Presentation; } - void getVector2s(std::vector &vec, size_t size) +}; + +template +struct NIFStream::conversion_handler +{ + typedef handler store_handler; + + static const bool FixedLength = store_handler::FixedLength; + static const size_t EncodedLength = store_handler::EncodedLength; + static const bool FileCompatibleLayout = false; + + static void extract (NIFStream & Stream, final_type & Value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + store_type StoreValue; + store_handler::extract (Stream, StoreValue); + Value = final_type (StoreValue); } - void getVector3s(std::vector &vec, size_t size) +}; + +template +struct NIFStream::conversion_handler +{ + typedef handler store_handler; + + static const bool FixedLength = store_handler::FixedLength; + static const size_t EncodedLength = store_handler::EncodedLength; + static const bool FileCompatibleLayout = store_handler::FileCompatibleLayout; + + static void extract (NIFStream & Stream, final_type & FinalValue) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + store_handler::extract (Stream, reinterpret_cast (FinalValue)); } - void getVector4s(std::vector &vec, size_t size) +}; + +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; + +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; + +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; + +template <> struct NIFStream::handler +{ + static const bool FixedLength = true; + static const size_t EncodedLength = + handler ::EncodedLength + + handler ::EncodedLength + + handler ::EncodedLength; + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream & stream, Transformation & value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); - } - void getQuaternions(std::vector &quat, size_t size) - { - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); + stream.uncheckedRead (value.pos); + stream.uncheckedRead (value.rotation); + stream.uncheckedRead (value.scale); } }; From e7665582ad9b855522b37d955997df527254a01d Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 22:51:06 -0800 Subject: [PATCH 383/817] reworked Nif::KeyListT into Nif::CurveT Renamed Nif:KeyListT to Nif::CurveT, moved it into its own file and changed its implementation so that on compatible platforms, the entire array of key-frames can be read in a single read call. Added a helper class called Nif::CurveT::interpolator to allow other code to easily evaluate the curve. Reworked part of the skeletonLoader code to use the interpolator to simplify its own logic. --- components/nif/curve.hpp | 424 +++++++++++++++++++++++++++ components/nif/data.hpp | 17 +- components/nif/niffile.hpp | 76 ----- components/nifogre/ogrenifloader.cpp | 113 ++----- components/nifogre/skeleton.cpp | 107 ++----- 5 files changed, 481 insertions(+), 256 deletions(-) create mode 100644 components/nif/curve.hpp diff --git a/components/nif/curve.hpp b/components/nif/curve.hpp new file mode 100644 index 000000000..9a71f0923 --- /dev/null +++ b/components/nif/curve.hpp @@ -0,0 +1,424 @@ +#ifndef _NIF_KEYLIST_H_ +#define _NIF_KEYLIST_H_ + +#include + +namespace Nif +{ + +template +void bubble_sort (iterator begin, iterator end, predicate const & in_order) +{ + if (end > begin) + { + for (iterator i = begin; i != end - 1; ++i) + { + if (in_order (*(i+0), *(i+1))) + continue; + + for (iterator j = i; j >= begin; --j) + { + std::swap (*(j+0), *(j+1)); + + if (in_order (*(j+0), *(j+1))) + break; + } + } + } +} + +template +value_type linear_interpolate (float amount, value_type prev, value_type next) +{ + return prev + (next - prev) * amount; +} + +inline +Ogre::Quaternion linear_interpolate (float amount, Ogre::Quaternion prev, Ogre::Quaternion next) +{ + return Ogre::Quaternion::nlerp (amount, prev, next); +} + +template +struct KeyT { + + static const size_t EncodedLength = + NIFStream::handler ::EncodedLength + + NIFStream::handler ::EncodedLength + ; + + float mTime; + value_type mValue; + + void extract (NIFStream &nif) + { + nif.uncheckedRead (mTime); + nif.uncheckedRead (mValue); + } + + static bool in_order (KeyT const & l, KeyT const & r) + { + return l.mTime < r.mTime; + } + + template + struct NIFStream_handler + { + static const bool FixedLength = true; + static const size_t EncodedLength = derived_type::EncodedLength; + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream& Stream, KeyT & Value) + { + static_cast (Value).extract (Stream); + } + }; +}; + +template +struct LinearKeyT : KeyT +{ + static T interpolate (LinearKeyT * prev, LinearKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } +}; + +template +struct QuadraticKeyT : KeyT +{ + static const size_t EncodedLength = + KeyT ::EncodedLength + + NIFStream::handler ::EncodedLength * 2 + ; + + T mForwardValue; + T mBackwardValue; + + static T interpolate (QuadraticKeyT * prev, QuadraticKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } + + void extract (NIFStream &nif) + { + KeyT::extract (nif); + + nif.uncheckedRead (mForwardValue); + nif.uncheckedRead (mBackwardValue); + } +}; + +template +struct TbcKeyT : KeyT +{ + static const size_t EncodedLength = + KeyT ::EncodedLength + + NIFStream::handler ::EncodedLength * 3 + ; + + float mTension; + float mBias; + float mContinuity; + + static T interpolate (TbcKeyT * prev, TbcKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } + + void extract (NIFStream &nif) + { + KeyT::extract (nif); + + nif.uncheckedRead (mTension); + nif.uncheckedRead (mBias); + nif.uncheckedRead (mContinuity); + } +}; + +// register NIFStream extraction handlers for KeyT derivatives +template struct NIFStream::handler < LinearKeyT > : KeyT ::template NIFStream_handler < LinearKeyT > {}; +template struct NIFStream::handler < QuadraticKeyT > : KeyT ::template NIFStream_handler < QuadraticKeyT > {}; +template struct NIFStream::handler < TbcKeyT > : KeyT ::template NIFStream_handler < TbcKeyT > {}; + +struct Curve +{ + static const int sLinearInterpolation = 1; + static const int sQuadraticInterpolation = 2; + static const int sTBCInterpolation = 3; +}; + +template +struct CurveT : Curve { + + typedef KeyT BaseKey; + typedef TbcKeyT TcbKey; + typedef LinearKeyT LinearKey; + typedef QuadraticKeyT QuadraticKey; + + union keys { + LinearKey* Linear; + QuadraticKey* Quadratic; + TcbKey* Tcb; + }; + + class interpolator; + + int mInterpolationType; + size_t mSize; + keys mKeys; + + value_type sample (float time) const; + + KeyT const * const & keyAtIndex (size_t Index) const + { + switch (mInterpolationType) + { + case sLinearInterpolation: return mKeys.Linear + Index; + case sQuadraticInterpolation: return mKeys.Quadratic + Index; + case sTBCInterpolation: return mKeys.Tcb + Index; + } + } + + void read(NIFStream *nif, bool force=false) + { + size_t count = nif->getInt(); + + mSize = 0; + + if(count > 0 || force) + { + mInterpolationType = nif->getInt(); + + assert (mInterpolationType >= sLinearInterpolation && mInterpolationType <= sTBCInterpolation); + + if (count > 0) + { + if(mInterpolationType == sLinearInterpolation) + read_keys (nif, mKeys.Linear, count); + else if(mInterpolationType == sQuadraticInterpolation) + read_keys (nif, mKeys.Quadratic, count); + else if(mInterpolationType == sTBCInterpolation) + read_keys (nif, mKeys.Tcb, count); + else + nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + } + } + else + mInterpolationType = sLinearInterpolation; + } + + CurveT () { init (); } + CurveT (CurveT const & k) { init (k); } + //CurveT (CurveT && k) { init (); swap (std::move (k)); } + ~CurveT () { dest (); } + + operator bool () const { return mSize > 0; } + + //void operator = (CurveT && k) { swap(k); } + void operator = (CurveT const & k) { dest (); init (k); } + + void swap (CurveT & k) + { + std::swap (mSize, k.mSize); + std::swap (mInterpolationType, k.mInterpolationType); + std::swap (mKeys, k.mKeys); + } + +private: + + void init () + { + mSize = 0; + } + + void init (CurveT const & k) + { + mInterpolationType = k.mInterpolationType; + switch (mInterpolationType) + { + default: + case sLinearInterpolation: + mKeys.Linear = new LinearKey [k.mSize]; + memcpy (mKeys.Linear, k.mKeys.Linear, sizeof (LinearKey) * k.mSize); + mSize = k.mSize; + break; + case sQuadraticInterpolation: + mKeys.Quadratic = new QuadraticKey [k.mSize]; + memcpy (mKeys.Quadratic, k.mKeys.Quadratic, sizeof (QuadraticKey) * k.mSize); + mSize = k.mSize; + break; + case sTBCInterpolation: + mKeys.Tcb = new TcbKey [k.mSize]; + memcpy (mKeys.Tcb, k.mKeys.Tcb, sizeof (TcbKey) * k.mSize); + mSize = k.mSize; + break; + } + } + + void dest () + { + if (mSize > 0) + { + switch (mInterpolationType) + { + case sLinearInterpolation: delete mKeys.Linear; break; + case sQuadraticInterpolation: delete mKeys.Quadratic; break; + case sTBCInterpolation: delete mKeys.Tcb; break; + } + } + } + + template + void read_keys (NIFStream *nif, T * & store, size_t count) + { + store = new T [count]; + + mSize = count; + + nif->getArray (store, count); + + //NOTE: Is this really necessary? It seems reasonable to assume that + // animation data is already sorted by time... + // verified no out of order frames in GOTY edition + bubble_sort (store, store+count, T::in_order); + } +}; + +template +class CurveT::interpolator +{ + template + struct impl + { + key_type *Cur, *End; + + void init (key_type * Beg, size_t Len) + { + if (Len > 0) + { + Cur = Beg; + End = Beg + Len - 1; + } + else + { + Cur = End = NULL; + } + } + + bool hasData () const + { + return Cur && Cur <= End; + } + + value_type valueAt (float time) + { + while ((Cur < End) && (time >= Cur [1].mTime)) + ++Cur; + + if (Cur < End) + { + if (time > Cur->mTime) + { + key_type * Nxt = Cur + 1; + + float offset = time - Cur->mTime; + float length = Nxt->mTime - Cur->mTime; + + return key_type::interpolate (Cur, Nxt, offset / length); + } + else + return Cur->mValue; + } + else + return End->mValue; + } + + float curTime () const + { + return (Cur != NULL) ? Cur->Time : FLT_MIN; + } + + float nextTime () const + { + return Cur < End ? (Cur + 1)->mTime : FLT_MAX; + } + }; + +public: + + int mInterpolationType; + union { + impl Linear; + impl Quadratic; + impl Tcb; + }; + + interpolator (CurveT const & Curve) + { + mInterpolationType = Curve.mInterpolationType; + + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: Linear .init (Curve.mKeys.Linear, Curve.mSize); break; + case Curve::sQuadraticInterpolation: Quadratic.init (Curve.mKeys.Quadratic, Curve.mSize); break; + case Curve::sTBCInterpolation: Tcb .init (Curve.mKeys.Tcb, Curve.mSize); break; + } + } + + // return true if there is any value(s) in this curve + float hasData () const + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .hasData (); + case Curve::sQuadraticInterpolation: return Quadratic.hasData (); + case Curve::sTBCInterpolation: return Tcb .hasData (); + } + } + + // return the timestamp of the next key-frame, or FLT_MAX if + // there are no more key-frames, valid if hasData returns false + float nextTime () const + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .nextTime (); + case Curve::sQuadraticInterpolation: return Quadratic.nextTime (); + case Curve::sTBCInterpolation: return Tcb .nextTime (); + } + } + + // return the value of the curve at the specified time + // the passed in time should never exceed the result of + // nextTime, not valid if hasData returns false + value_type valueAt (float time) + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .valueAt (time); + case Curve::sQuadraticInterpolation: return Quadratic.valueAt (time); + case Curve::sTBCInterpolation: return Tcb .valueAt (time); + } + } +}; + +template +value_type CurveT::sample (float time) const +{ + interpolator i (*this); + return i.valueAt (time); +} + +typedef CurveT FloatCurve; +typedef CurveT Vector3Curve; +typedef CurveT Vector4Curve; +typedef CurveT QuaternionCurve; + +} + +#endif diff --git a/components/nif/data.hpp b/components/nif/data.hpp index f1f34184b..d46f99abb 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -25,6 +25,7 @@ #define OPENMW_COMPONENTS_NIF_DATA_HPP #include "controlled.hpp" +#include "curve.hpp" #include #include @@ -211,7 +212,7 @@ public: class NiPosData : public Record { public: - Vector3KeyList mKeyList; + Vector3Curve mKeyList; void read(NIFStream *nif) { @@ -222,7 +223,7 @@ public: class NiUVData : public Record { public: - FloatKeyList mKeyList[4]; + FloatCurve mKeyList[4]; void read(NIFStream *nif) { @@ -234,7 +235,7 @@ public: class NiFloatData : public Record { public: - FloatKeyList mKeyList; + FloatCurve mKeyList; void read(NIFStream *nif) { @@ -284,7 +285,7 @@ public: class NiColorData : public Record { public: - Vector4KeyList mKeyList; + Vector4Curve mKeyList; void read(NIFStream *nif) { @@ -389,7 +390,7 @@ public: struct NiMorphData : public Record { struct MorphData { - FloatKeyList mData; + FloatCurve mData; std::vector mVertices; }; std::vector mMorphs; @@ -412,9 +413,9 @@ struct NiMorphData : public Record struct NiKeyframeData : public Record { - QuaternionKeyList mRotations; - Vector3KeyList mTranslations; - FloatKeyList mScales; + QuaternionCurve mRotations; + Vector3Curve mTranslations; + FloatCurve mScales; void read(NIFStream *nif) { diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 6e629772e..83cc6ac8f 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -132,81 +132,5 @@ public: size_t numRoots() { return roots.size(); } }; - -template -struct KeyT { - float mTime; - T mValue; - T mForwardValue; // Only for Quadratic interpolation - T mBackwardValue; // Only for Quadratic interpolation - float mTension; // Only for TBC interpolation - float mBias; // Only for TBC interpolation - float mContinuity; // Only for TBC interpolation -}; -typedef KeyT FloatKey; -typedef KeyT Vector3Key; -typedef KeyT Vector4Key; -typedef KeyT QuaternionKey; - -template -struct KeyListT { - typedef std::vector< KeyT > VecType; - - static const int sLinearInterpolation = 1; - static const int sQuadraticInterpolation = 2; - static const int sTBCInterpolation = 3; - - int mInterpolationType; - VecType mKeys; - - void read(NIFStream *nif, bool force=false) - { - size_t count = nif->getInt(); - if(count == 0 && !force) - return; - - mInterpolationType = nif->getInt(); - mKeys.resize(count); - if(mInterpolationType == sLinearInterpolation) - { - for(size_t i = 0;i < count;i++) - { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); - } - } - else if(mInterpolationType == sQuadraticInterpolation) - { - for(size_t i = 0;i < count;i++) - { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); - key.mForwardValue = (nif->*getValue)(); - key.mBackwardValue = (nif->*getValue)(); - } - } - else if(mInterpolationType == sTBCInterpolation) - { - for(size_t i = 0;i < count;i++) - { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); - key.mTension = nif->getFloat(); - key.mBias = nif->getFloat(); - key.mContinuity = nif->getFloat(); - } - } - else - nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); - } -}; -typedef KeyListT FloatKeyList; -typedef KeyListT Vector3KeyList; -typedef KeyListT Vector4KeyList; -typedef KeyListT QuaternionKeyList; - } // Namespace #endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a26f43131..f381dc239 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -166,9 +166,9 @@ public: class Value : public NodeTargetValue { private: - Nif::QuaternionKeyList mRotations; - Nif::Vector3KeyList mTranslations; - Nif::FloatKeyList mScales; + Nif::QuaternionCurve mRotations; + Nif::Vector3Curve mTranslations; + Nif::FloatCurve mScales; public: Value(Ogre::Node *target, const Nif::NiKeyframeData *data) @@ -186,68 +186,16 @@ public: virtual void setValue(Ogre::Real time) { - if(mRotations.mKeys.size() > 0) - { - if(time <= mRotations.mKeys.front().mTime) - mNode->setOrientation(mRotations.mKeys.front().mValue); - else if(time >= mRotations.mKeys.back().mTime) - mNode->setOrientation(mRotations.mKeys.back().mValue); - else - { - Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); - for(;iter != mRotations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; + if(mRotations) + mNode->setOrientation(mRotations.sample (time)); - Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); - break; - } - } - } - if(mTranslations.mKeys.size() > 0) - { - if(time <= mTranslations.mKeys.front().mTime) - mNode->setPosition(mTranslations.mKeys.front().mValue); - else if(time >= mTranslations.mKeys.back().mTime) - mNode->setPosition(mTranslations.mKeys.back().mValue); - else - { - Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); - for(;iter != mTranslations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; + if(mTranslations) + mNode->setPosition(mTranslations.sample (time)); - Nif::Vector3KeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); - break; - } - } - } - if(mScales.mKeys.size() > 0) + if(mScales) { - if(time <= mScales.mKeys.front().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); - else if(time >= mScales.mKeys.back().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); - else - { - Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); - for(;iter != mScales.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); - break; - } - } + float s = mScales.sample (time); + mNode->setScale(s, s, s); } } }; @@ -262,30 +210,14 @@ public: { private: Ogre::MaterialPtr mMaterial; - Nif::FloatKeyList mUTrans; - Nif::FloatKeyList mVTrans; - Nif::FloatKeyList mUScale; - Nif::FloatKeyList mVScale; + Nif::FloatCurve mUTrans; + Nif::FloatCurve mVTrans; + Nif::FloatCurve mUScale; + Nif::FloatCurve mVScale; - static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) + static float lookupValue(const Nif::FloatCurve &keys, float time, float def) { - if(keys.mKeys.size() == 0) - return def; - - if(time <= keys.mKeys.front().mTime) - return keys.mKeys.front().mValue; - - Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()+1); - for(;iter != keys.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - return last->mValue + ((iter->mValue - last->mValue)*a); - } - return keys.mKeys.back().mValue; + return keys ? keys.sample (time) : def; } public: @@ -392,18 +324,19 @@ class NIFObjectLoader const Nif::NiColorData *clrdata = cl->data.getPtr(); Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator"); - size_t num_colors = std::min(6, clrdata->mKeyList.mKeys.size()); + size_t num_colors = std::min(6, clrdata->mKeyList.mSize); for(size_t i = 0;i < num_colors;i++) { + Nif::Vector4Curve::BaseKey const * Key = clrdata->mKeyList.keyAtIndex (i); Ogre::ColourValue color; - color.r = clrdata->mKeyList.mKeys[i].mValue[0]; - color.g = clrdata->mKeyList.mKeys[i].mValue[1]; - color.b = clrdata->mKeyList.mKeys[i].mValue[2]; - color.a = clrdata->mKeyList.mKeys[i].mValue[3]; + color.r = Key->mValue[0]; + color.g = Key->mValue[1]; + color.b = Key->mValue[2]; + color.a = Key->mValue[3]; affector->setParameter("colour"+Ogre::StringConverter::toString(i), Ogre::StringConverter::toString(color)); affector->setParameter("time"+Ogre::StringConverter::toString(i), - Ogre::StringConverter::toString(clrdata->mKeyList.mKeys[i].mTime)); + Ogre::StringConverter::toString(Key->mTime)); } } else if(e->recType == Nif::RC_NiParticleRotation) diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index e97e91ef0..66060b967 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -10,6 +10,11 @@ namespace NifOgre { +template +static value_type min (value_type V0, value_type V1, value_type V2, value_type V3) +{ + return std::min (std::min (V0, V1), std::min (V2, V3)); +} void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { @@ -22,15 +27,6 @@ void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string & continue; const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - Ogre::Bone *bone = skel->getBone(targets[i]); // NOTE: For some reason, Ogre doesn't like the node track ID being different from // the bone ID @@ -38,83 +34,30 @@ void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string & anim->getNodeTrack(bone->getHandle()) : anim->createNodeTrack(bone->getHandle(), bone); - Ogre::Quaternion lastquat, curquat; - Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); - Ogre::Vector3 lastscale(1.0f), curscale(1.0f); - if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); + Nif::QuaternionCurve::interpolator rci (kf->mRotations); + Nif::Vector3Curve::interpolator tci (kf->mTranslations); + Nif::FloatCurve::interpolator sci (kf->mScales); - bool didlast = false; - while(!didlast) + float next_timestamp = startTime; + + for (;;) { - float curtime = std::numeric_limits::max(); - - //Get latest time - if(quatiter != quatkeys.mKeys.end()) - curtime = std::min(curtime, quatiter->mTime); - if(traniter != trankeys.mKeys.end()) - curtime = std::min(curtime, traniter->mTime); - if(scaleiter != scalekeys.mKeys.end()) - curtime = std::min(curtime, scaleiter->mTime); - - curtime = std::max(curtime, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } + static const Ogre::Vector3 one (1,1,1); Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; - float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); - kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); - } - if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) - kframe->setTranslate(curtrans); - else - { - Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; - float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); - kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); - } - if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) - kframe->setScale(curscale); - else - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } + kframe = nodetrack->createNodeKeyFrame (next_timestamp); + + if (rci.hasData ()) kframe->setRotation (rci.valueAt (next_timestamp)); + if (tci.hasData ()) kframe->setTranslate (tci.valueAt (next_timestamp)); + if (sci.hasData ()) kframe->setScale (sci.valueAt (next_timestamp)*one); + + if (next_timestamp >= stopTime) + break; + + next_timestamp = min (stopTime, + rci.nextTime (), + tci.nextTime (), + sci.nextTime ()); } } anim->optimise(); From 6dbb53493b34c6430e8bdf0ea0d4f411facfa1b5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 3 Jan 2013 23:39:00 -0800 Subject: [PATCH 384/817] enable move construction/assignment to key ESM data structure to reduce sorting costs --- components/esm/defs.hpp | 10 +++++++ components/esm/loaddial.hpp | 36 ++++++++++++++++++++++ components/esm/loadinfo.hpp | 60 +++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index bd86f9ba0..3dc498a63 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -1,6 +1,16 @@ #ifndef OPENMW_ESM_DEFS_H #define OPENMW_ESM_DEFS_H +#if _MSC_VER >= 1600 +#define OPENMW_ESM_ENABLE_CPP11_MOVE +#define OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(Class) \ + Class () {} \ + Class (Class const & that) { copy (*this, that); } \ + Class (Class && that) { move (*this, that); } \ + Class & operator = (Class const & that) { copy (*this, that); return *this; } \ + Class & operator = (Class && that) { move (*this, that); return *this; } +#endif + #include namespace ESM diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 61f3f763d..bb726b855 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "loadinfo.hpp" @@ -35,6 +36,41 @@ struct Dialogue void load(ESMReader &esm); void save(ESMWriter &esm); + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(Dialogue) + + static void copy (Dialogue & d, Dialogue const & s) + { + d.mId = s.mId; + d.mType = s.mType; + d.mInfo = s.mInfo; + } + static void move (Dialogue & d, Dialogue & s) + { + d.mId = std::move (s.mId); + d.mType = std::move (s.mType); + d.mInfo = std::move (s.mInfo); + } +#endif }; } + +/* + custom swap to prevent memory allocations and deallocations for mId and mInfo + while sorting +*/ +namespace std +{ + template <> inline + void swap (ESM::Dialogue & Left, ESM::Dialogue & Right) + { +#define _swp(id) std::swap (Left.id, Right.id); + _swp(mId); + _swp(mType); + _swp(mInfo); +#undef _swp + } +} + #endif diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 2361ed9eb..c7608ca86 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -43,6 +43,22 @@ struct DialInfo { std::string mSelectRule; // This has a complicated format Variant mValue; + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(SelectStruct) + + static void copy (SelectStruct & d, SelectStruct const & s) + { + d.mSelectRule = s.mSelectRule; + d.mValue = s.mValue; + } + + static void move (SelectStruct & d, SelectStruct & s) + { + d.mSelectRule = std::move (s.mSelectRule); + d.mValue = std::move (s.mValue); + } +#endif // OPENMW_ESM_ENABLE_CPP11_MOVE }; // Journal quest indices (introduced with the quest system in Tribunal) @@ -100,6 +116,50 @@ struct DialInfo void load(ESMReader &esm); void save(ESMWriter &esm); + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(DialInfo) + + static void copy (DialInfo & d, DialInfo const & s) + { + d.mData = s.mData; + d.mSelects = s.mSelects; + d.mId = s.mId; + d.mPrev = s.mPrev; + d.mNext = s.mNext; + d.mActor = s.mActor; + d.mRace = s.mRace; + d.mClass = s.mClass; + d.mNpcFaction = s.mNpcFaction; + d.mPcFaction = s.mPcFaction; + d.mCell = s.mCell; + d.mSound = s.mSound; + d.mResponse = s.mResponse; + d.mResultScript = s.mResultScript; + d.mFactionLess = s.mFactionLess; + d.mQuestStatus = s.mQuestStatus; + } + + static void move (DialInfo & d, DialInfo & s) + { + d.mData = std::move (s.mData); + d.mSelects = std::move (s.mSelects); + d.mId = std::move (s.mId); + d.mPrev = std::move (s.mPrev); + d.mNext = std::move (s.mNext); + d.mActor = std::move (s.mActor); + d.mRace = std::move (s.mRace); + d.mClass = std::move (s.mClass); + d.mNpcFaction = std::move (s.mNpcFaction); + d.mPcFaction = std::move (s.mPcFaction); + d.mCell = std::move (s.mCell); + d.mSound = std::move (s.mSound); + d.mResponse = std::move (s.mResponse); + d.mResultScript = std::move (s.mResultScript); + d.mFactionLess = std::move (s.mFactionLess); + d.mQuestStatus = std::move (s.mQuestStatus); + } +#endif // OPENMW_ESM_ENABLE_CPP11_MOVE }; } From 8dad04eef19e7471787615348181d6c32ed6e82a Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 13 Jan 2013 13:03:11 -0800 Subject: [PATCH 385/817] hid JournalWindow behind IJournalWindow interface, and put its entire implementation, class definition and all, into journalwindow.cpp --- apps/openmw/mwgui/journalwindow.cpp | 223 ++++++++++++++----------- apps/openmw/mwgui/journalwindow.hpp | 34 +--- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +- 4 files changed, 137 insertions(+), 126 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 23588a4af..9540e6986 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -5,6 +5,16 @@ #include "../mwbase/journal.hpp" #include "../mwbase/soundmanager.hpp" +#include +#include +#include +#include + +#include "windowbase.hpp" +#include "imagebutton.hpp" + +using namespace MWGui; + namespace { struct book @@ -77,116 +87,135 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) //std::string } - -MWGui::JournalWindow::JournalWindow () - : WindowBase("openmw_journal.layout") - , mPageNumber(0) +namespace { - mMainWidget->setVisible(false); - //setCoord(0,0,498, 342); - center(); - - getWidget(mLeftTextWidget, "LeftText"); - getWidget(mRightTextWidget, "RightText"); - getWidget(mPrevBtn, "PrevPageBTN"); - mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyPrevPage); - getWidget(mNextBtn, "NextPageBTN"); - mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyNextPage); - //MyGUI::ItemBox* list = new MyGUI::ItemBox(); - //list->addItem("qaq","aqzazaz"); - //mScrollerWidget->addChildItem(list); - //mScrollerWidget->addItem("dserzt",MyGUI::UString("fedgdfg")); - //mEditWidget->addText("ljblsxdvdsfvgedfvdfvdkjfghldfjgn sdv,nhsxl;vvn lklksbvlksb lbsdflkbdSLKJGBLskdhbvlshow(); - //mEditWidget->setEditStatic(true); - mLeftTextWidget->addText("left texxxt "); - mLeftTextWidget->setEditReadOnly(true); - mRightTextWidget->setEditReadOnly(true); - mRightTextWidget->setEditStatic(true); - mLeftTextWidget->setEditStatic(true); - mRightTextWidget->addText("Right texxt "); - - //std::list list = formatText("OpenMW rgh dsfg sqef srg ZT uzql n ZLIEHRF LQSJH GLOIjf qjfmj hslkdgn jlkdjhg qlr isgli shli uhs fiuh qksf cg ksjnf lkqsnbf ksbf sbfkl zbf kuyzflkj sbgdfkj zlfh ozhjfmo hzmfh lizuf rty qzt ezy tkyEZT RYYJ DG fgh is an open-source implementation of the game engine found in the game Morrowind. This is a dumb test text msodjbg smojg smoig fiiinnn"); - //std::list list = formatText(); - //displayLeftText(list.front()); -} - -void MWGui::JournalWindow::open() -{ - mPageNumber = 0; - if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) + struct JournalWindow : WindowBase, IJournalWindow { - book journal; - journal.endLine = 0; + MyGUI::EditPtr mLeftTextWidget; + MyGUI::EditPtr mRightTextWidget; + MWGui::ImageButton* mPrevBtn; + MWGui::ImageButton* mNextBtn; + std::vector mLeftPages; + std::vector mRightPages; + int mPageNumber; //store the number of the current left page - for(std::deque::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();++it) + JournalWindow () + : WindowBase("openmw_journal.layout") + , mPageNumber(0) { - std::string a = it->getText(MWBase::Environment::get().getWorld()->getStore()); - journal = formatText(a,journal,10,17); - journal.endLine = journal.endLine +1; - journal.pages.back() = journal.pages.back() + std::string("\n"); + mMainWidget->setVisible(false); + //setCoord(0,0,498, 342); + center(); + + getWidget(mLeftTextWidget, "LeftText"); + getWidget(mRightTextWidget, "RightText"); + getWidget(mPrevBtn, "PrevPageBTN"); + mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&JournalWindow::notifyPrevPage); + getWidget(mNextBtn, "NextPageBTN"); + mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&JournalWindow::notifyNextPage); + + + + mLeftTextWidget->setEditReadOnly(true); + mRightTextWidget->setEditReadOnly(true); + mRightTextWidget->setEditStatic(true); + mLeftTextWidget->setEditStatic(true); } - //std::string a = MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); - //std::list journal = formatText(a,10,20,1); - bool left = true; - for(std::list::iterator it = journal.pages.begin(); it != journal.pages.end();++it) + + void close() { - if(left) + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + } + + void open() + { + mPageNumber = 0; + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) { - mLeftPages.push_back(*it); + book journal; + journal.endLine = 0; + + for(std::deque::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();++it) + { + std::string a = it->getText(MWBase::Environment::get().getWorld()->getStore()); + journal = formatText(a,journal,10,17); + journal.endLine = journal.endLine +1; + journal.pages.back() = journal.pages.back() + std::string("\n"); + } + //std::string a = MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); + //std::list journal = formatText(a,10,20,1); + bool left = true; + for(std::list::iterator it = journal.pages.begin(); it != journal.pages.end();++it) + { + if(left) + { + mLeftPages.push_back(*it); + } + else + { + mRightPages.push_back(*it); + } + left = !left; + } + if(!left) mRightPages.push_back(""); + + mPageNumber = mLeftPages.size()-1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } else { - mRightPages.push_back(*it); + //std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); } - left = !left; } - if(!left) mRightPages.push_back(""); - mPageNumber = mLeftPages.size()-1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); + void setVisible (bool newValue) + { + WindowBase::setVisible (newValue); + } - } - else - { - //std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); - } + + void displayLeftText(std::string text) + { + mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength()); + mLeftTextWidget->addText(text); + } + + void displayRightText(std::string text) + { + mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength()); + mRightTextWidget->addText(text); + } + + + + void notifyNextPage(MyGUI::Widget* _sender) + { + if(mPageNumber < int(mLeftPages.size())-1) + { + std::string nextSound = "book page2"; + MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); + mPageNumber = mPageNumber + 1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } + } + + void notifyPrevPage(MyGUI::Widget* _sender) + { + if(mPageNumber > 0) + { + std::string prevSound = "book page"; + MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0); + mPageNumber = mPageNumber - 1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } + } + }; } -void MWGui::JournalWindow::displayLeftText(std::string text) -{ - mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength()); - mLeftTextWidget->addText(text); -} - -void MWGui::JournalWindow::displayRightText(std::string text) -{ - mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength()); - mRightTextWidget->addText(text); -} - - -void MWGui::JournalWindow::notifyNextPage(MyGUI::Widget* _sender) -{ - if(mPageNumber < int(mLeftPages.size())-1) - { - std::string nextSound = "book page2"; - MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); - mPageNumber = mPageNumber + 1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); - } -} - -void MWGui::JournalWindow::notifyPrevPage(MyGUI::Widget* _sender) -{ - if(mPageNumber > 0) - { - std::string prevSound = "book page"; - MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0); - mPageNumber = mPageNumber - 1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); - } -} +// glue the implementation to the interface +IJournalWindow * MWGui::IJournalWindow::create () { return new JournalWindow (); } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 27bf608e1..8f734dc24 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,39 +1,21 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H -#include - -#include "windowbase.hpp" -#include "imagebutton.hpp" +namespace MWBase { class WindowManager; } namespace MWGui { - class JournalWindow : public WindowBase + struct IJournalWindow { - public: - JournalWindow(); - virtual void open(); + /// construct a new instance of the one JournalWindow implementation + static IJournalWindow * create (); - private: - void displayLeftText(std::string text); - void displayRightText(std::string text); + /// destroy this instance of the JournalWindow implementation + virtual ~IJournalWindow () {}; - - /** - *Called when next/prev button is used. - */ - void notifyNextPage(MyGUI::Widget* _sender); - void notifyPrevPage(MyGUI::Widget* _sender); - - MyGUI::EditBox* mLeftTextWidget; - MyGUI::EditBox* mRightTextWidget; - MWGui::ImageButton* mPrevBtn; - MWGui::ImageButton* mNextBtn; - std::vector mLeftPages; - std::vector mRightPages; - int mPageNumber; //store the number of the current left page + /// show/hide the journal window + virtual void setVisible (bool newValue) = 0; }; - } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2171beaff..6b38042a6 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -145,7 +145,7 @@ namespace MWGui mMap = new MapWindow(cacheDir); mStatsWindow = new StatsWindow(); mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(); + mJournal = IJournalWindow::create(); mMessageBoxManager = new MessageBoxManager(); mInventoryWindow = new InventoryWindow(mDragAndDrop); mTradeWindow = new TradeWindow(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 652ad870f..43951d46a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -51,7 +51,7 @@ namespace MWGui class MainMenu; class StatsWindow; class InventoryWindow; - class JournalWindow; + class IJournalWindow; class CharacterCreation; class DragAndDrop; class ToolTips; @@ -253,7 +253,7 @@ namespace MWGui StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; - JournalWindow* mJournal; + IJournalWindow* mJournal; DialogueWindow *mDialogueWindow; ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; From 85595245abb777dc038785a42afbb3781e570238 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 01:00:11 -0800 Subject: [PATCH 386/817] Updated journal layout to match Bethesda's version more closely --- files/mygui/openmw_journal.layout | 94 +++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index fdf82e4de..addd4296d 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -2,24 +2,84 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 75757cb675f91b3e010221cb9687842c70f89009 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 10:43:41 -0800 Subject: [PATCH 387/817] Created a class to represent a stream of UTF8 characters. --- components/misc/utf8stream.hpp | 115 +++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 components/misc/utf8stream.hpp diff --git a/components/misc/utf8stream.hpp b/components/misc/utf8stream.hpp new file mode 100644 index 000000000..a491ed082 --- /dev/null +++ b/components/misc/utf8stream.hpp @@ -0,0 +1,115 @@ +#ifndef MISC_UTF8ITER_HPP +#define MISC_UTF8ITER_HPP + +#include + +class utf8_stream +{ +public: + + typedef uint32_t unicode_char; + typedef unsigned char const * point; + + static const unicode_char sBadChar = 0xFFFFFFFF; + + utf8_stream (point begin, point end) : + cur (begin), nxt (begin), end (end) + { + } + + utf8_stream (std::pair range) : + cur (range.first), nxt (range.first), end (range.second) + { + } + + bool eof () const + { + return cur == end; + } + + point current () const + { + return cur; + } + + unicode_char peek () + { + if (cur == nxt) + next (); + return val; + } + + unicode_char consume () + { + if (cur == nxt) + next (); + cur = nxt; + return val; + } + + static std::pair decode (point cur, point end) + { + if ((*cur & 0x80) == 0) + { + unicode_char chr = *cur++; + + return std::make_pair (chr, cur); + } + + int octets; + unicode_char chr; + + boost::tie (octets, chr) = octet_count (*cur++); + + if (octets > 5) + return std::make_pair (sBadChar, cur); + + auto eoc = cur + octets; + + if (eoc > end) + return std::make_pair (sBadChar, cur); + + while (cur != eoc) + { + if ((*cur & 0xC0) != 0x80) // check continuation mark + return std::make_pair (sBadChar, cur);; + + chr = (chr << 6) | unicode_char ((*cur++) & 0x3F); + } + + return std::make_pair (chr, cur); + } + +private: + + static std::pair octet_count (unsigned char octet) + { + int octets; + + unsigned char mark = 0xC0; + unsigned char mask = 0xE0; + + for (octets = 1; octets <= 5; ++octets) + { + if ((octet & mask) == mark) + break; + + mark = (mark >> 1) | 0x80; + mask = (mask >> 1) | 0x80; + } + + return std::make_pair (octets, octet & ~mask); + } + + void next () + { + boost::tie (val, nxt) = decode (nxt, end); + } + + point cur; + point nxt; + point end; + unicode_char val; +}; + +#endif \ No newline at end of file From 55ca037411de9f669da282c1c86203862e74b029 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 11:56:00 -0800 Subject: [PATCH 388/817] Created a MyGUI widget to present a page of formatted text. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/bookpage.cpp | 1204 ++++++++++++++++++++++++ apps/openmw/mwgui/bookpage.hpp | 120 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 4 files changed, 1327 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwgui/bookpage.cpp create mode 100644 apps/openmw/mwgui/bookpage.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f4fdcb390..fcd2c1450 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair repair soulgemdialog companionwindow + merchantrepair repair soulgemdialog companionwindow bookpage ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp new file mode 100644 index 000000000..4007dc1f1 --- /dev/null +++ b/apps/openmw/mwgui/bookpage.cpp @@ -0,0 +1,1204 @@ +#include "bookpage.hpp" + +#include "MyGUI_FontManager.h" +#include "MyGUI_RenderItem.h" +#include "MyGUI_RenderManager.h" +#include "MyGUI_TextureUtility.h" +#include "MyGUI_FactoryManager.h" + +#include + +#include + +namespace MWGui +{ + struct TypesetBook; + struct PageDisplay; + struct BookPage; +} + +using namespace MyGUI; +using namespace MWGui; + +static bool ucs_space (int code_point); +static bool ucs_line_break (int code_point); +static bool ucs_breaking_space (int code_point); + +struct IBookTypesetter::IStyle { virtual ~IStyle () {} }; + +struct MWGui::TypesetBook : ITypesetBook +{ + typedef std::vector content; + typedef std::list contents; + typedef utf8_stream::point utf8_point; + typedef std::pair range; + + struct style : IBookTypesetter::IStyle + { + IFont* Font; + Colour HotColour; + Colour ActiveColour; + Colour NormalColour; + interactive_id InteractiveId; + + bool match (IFont* tstFont, Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return (Font == tstFont) && + partal_match (tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId); + } + + bool match (char const * tstFont, Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return (Font->getResourceName () == tstFont) && + partal_match (tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId); + } + + bool partal_match (Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return + (HotColour == tstHotColour ) && + (ActiveColour == tstActiveColour ) && + (NormalColour == tstNormalColour ) && + (InteractiveId == tstInteractiveId ) ; + } + }; + + typedef std::list