diff --git a/.travis.yml b/.travis.yml index 374b38ce0..5c69f49f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,8 @@ 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-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 libbullet-dev libogre-static-dev libmygui-static-dev libsdl2-static-dev - sudo mkdir /usr/src/gtest/build - cd /usr/src/gtest/build - sudo cmake .. -DBUILD_SHARED_LIBS=1 @@ -27,7 +26,7 @@ before_script: - cd - - mkdir build - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBOOST_STATIC=1 -DSDL2_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 script: - make -j4 after_script: diff --git a/CMakeLists.txt b/CMakeLists.txt index b989297b3..f2b1fcd4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,10 @@ if (APPLE) set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app") set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}") + + set(CMAKE_EXE_LINKER_FLAGS "-F /Library/Frameworks") + set(CMAKE_SHARED_LINKER_FLAGS "-F /Library/Frameworks") + set(CMAKE_MODULE_LINKER_FLAGS "-F /Library/Frameworks") endif (APPLE) # Macros @@ -15,7 +19,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 23) +set (OPENMW_VERSION_MINOR 24) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -27,6 +31,7 @@ configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_ option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) +option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) # Apps and tools option(BUILD_BSATOOL "build BSA extractor" OFF) @@ -77,7 +82,13 @@ set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/particles.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp + ${LIBDIR}/openengine/ogre/imagerotate.cpp ) + +if (APPLE) + set(OENGINE_OGRE ${OENGINE_OGRE} ${LIBDIR}/openengine/ogre/osx_utils.mm) +endif () + set(OENGINE_GUI ${LIBDIR}/openengine/gui/manager.cpp ) @@ -181,6 +192,12 @@ if (UNIX AND NOT APPLE) find_package (Threads) endif() +include (CheckIncludeFileCXX) +check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP) +if (HAVE_UNORDERED_MAP) + add_definitions(-DHAVE_UNORDERED_MAP) +endif () + set(BOOST_COMPONENTS system filesystem program_options thread date_time wave) @@ -191,7 +208,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) @@ -205,7 +222,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} @@ -214,7 +232,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 @@ -287,9 +305,12 @@ configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local "${OpenMW_BINARY_DIR}/openmw.cfg") + configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg.install") +configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg + "${OpenMW_BINARY_DIR}/opencs.cfg") if (NOT WIN32 AND NOT APPLE) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop @@ -300,15 +321,15 @@ endif() # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) - add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long) + SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") # Silence warnings in OGRE headers. Remove once OGRE got fixed! - add_definitions (-Wno-ignored-qualifiers) + SET(CMAKE_CXX_FLAGS "-Wno-ignored-qualifiers ${CMAKE_CXX_FLAGS}") execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) - add_definitions (-Wno-unused-but-set-parameter) + SET(CMAKE_CXX_FLAGS "-Wno-unused-but-set-parameter ${CMAKE_CXX_FLAGS}") endif("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) endif (CMAKE_COMPILER_IS_GNUCC) @@ -334,6 +355,7 @@ if(DPKG_PROGRAM) INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "../etc/openmw/" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") #Install resources INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "share/games/openmw/" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources") @@ -349,8 +371,8 @@ if(DPKG_PROGRAM) Data files from the original game is required to run it.") SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") - SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") - 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_PACKAGE_EXECUTABLES "openmw;OpenMW bsatool;Bsatool esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), 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") @@ -437,6 +459,7 @@ endif(WIN32) # Extern add_subdirectory (extern/shiny) add_subdirectory (extern/oics) +add_subdirectory (extern/sdl4ogre) # Components add_subdirectory (components) @@ -572,6 +595,7 @@ if (APPLE) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) + install(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) set(CPACK_GENERATOR "DragNDrop") set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) @@ -687,6 +711,7 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) #INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${SYSCONFDIR}" ) INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" ) INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" ) + INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${SYSCONFDIR}" ) # Install resources INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) diff --git a/apps/esmtool/CMakeLists.txt b/apps/esmtool/CMakeLists.txt index 5c588fb29..1d0026215 100644 --- a/apps/esmtool/CMakeLists.txt +++ b/apps/esmtool/CMakeLists.txt @@ -17,11 +17,6 @@ target_link_libraries(esmtool components ) -#if (APPLE) -# find_library(CARBON_FRAMEWORK Carbon) -# target_link_libraries(openmw ${CARBON_FRAMEWORK}) -#endif (APPLE) - if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(esmtool gcov) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 8e0900ba0..a60e9f0e2 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -108,11 +108,26 @@ bool parseOptions (int argc, char** argv, Arguments &info) // there might be a better way to do this bpo::options_description all; all.add(desc).add(hidden); - bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv) - .options(all).positional(p).run(); - bpo::variables_map variables; - bpo::store(valid_opts, variables); + + try + { + bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv) + .options(all).positional(p).run(); + + bpo::store(valid_opts, variables); + } + catch(boost::program_options::unknown_option & x) + { + std::cerr << "ERROR: " << x.what() << std::endl; + return false; + } + catch(boost::program_options::invalid_command_line_syntax & x) + { + std::cerr << "ERROR: " << x.what() << std::endl; + return false; + } + bpo::notify(variables); if (variables.count ("help")) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index 0c93474da..bff26b63c 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -90,6 +90,7 @@ target_link_libraries(omwlauncher ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${OGRE_STATIC_PLUGINS} + ${SDL2_LIBRARY} ${QT_LIBRARIES} components ) diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 700ba3db9..1bbf7f897 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -35,13 +36,14 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &g setupUi(this); // Set the maximum res we can set in windowed mode - QRect res = QApplication::desktop()->screenGeometry(); + QRect res = getMaximumResolution(); customWidthSpinBox->setMaximum(res.width()); customHeightSpinBox->setMaximum(res.height()); connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&))); connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int))); connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool))); + connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int))); } @@ -144,17 +146,41 @@ bool GraphicsPage::setupOgre() } antiAliasingComboBox->clear(); - resolutionComboBox->clear(); antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); - // Load the rest of the values - loadSettings(); return true; } -void GraphicsPage::loadSettings() +bool GraphicsPage::setupSDL() { + int displays = SDL_GetNumVideoDisplays(); + + if (displays < 0) + { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error receiving number of screens")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.exec(); + return false; + } + + for (int i = 0; i < displays; i++) + { + screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1)); + } + + return true; +} + +bool GraphicsPage::loadSettings() +{ + if (!setupSDL()) + return false; + if (!setupOgre()) + return false; + if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) vSyncCheckBox->setCheckState(Qt::Checked); @@ -168,6 +194,9 @@ void GraphicsPage::loadSettings() QString width = mGraphicsSettings.value(QString("Video/resolution x")); QString height = mGraphicsSettings.value(QString("Video/resolution y")); QString resolution = width + QString(" x ") + height; + QString screen = mGraphicsSettings.value(QString("Video/screen")); + + screenComboBox->setCurrentIndex(screen.toInt()); int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith); @@ -180,6 +209,8 @@ void GraphicsPage::loadSettings() customHeightSpinBox->setValue(height.toInt()); } + + return true; } void GraphicsPage::saveSettings() @@ -205,6 +236,8 @@ void GraphicsPage::saveSettings() mGraphicsSettings.setValue(QString("Video/resolution x"), QString::number(customWidthSpinBox->value())); mGraphicsSettings.setValue(QString("Video/resolution y"), QString::number(customHeightSpinBox->value())); } + + mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex())); } QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer) @@ -240,64 +273,83 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy return result; } -QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) +QStringList GraphicsPage::getAvailableResolutions(int screen) { - QString key("Video Mode"); QStringList result; + SDL_DisplayMode mode; + int modeIndex, modes = SDL_GetNumDisplayModes(screen); - uint row = 0; - Ogre::ConfigOptionMap options = renderer->getConfigOptions(); - - for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++) + if (modes < 0) { - if (key.toStdString() != i->first) - continue; - - Ogre::StringVector::iterator opt_it; - uint idx = 0; - - for (opt_it = i->second.possibleValues.begin (); - opt_it != i->second.possibleValues.end (); opt_it++, idx++) - { - QRegExp resolutionRe(QString("(\\d+) x (\\d+).*")); - QString resolution = QString::fromStdString(*opt_it).simplified(); - - if (resolutionRe.exactMatch(resolution)) { - - int width = resolutionRe.cap(1).toInt(); - int height = resolutionRe.cap(2).toInt(); - - QString aspect = getAspect(width, height); - QString cleanRes = resolutionRe.cap(1) + QString(" x ") + resolutionRe.cap(2); - - if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { - cleanRes.append(tr("\t(Wide ") + aspect + ")"); - - } else if (aspect == QLatin1String("4:3")) { - cleanRes.append(tr("\t(Standard 4:3)")); - } - // do not add duplicate resolutions - if (!result.contains(cleanRes)) - result.append(cleanRes); - } - } + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error receiving resolutions")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
SDL_GetNumDisplayModes failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.exec(); + return result; } - // Sort the resolutions in descending order - qSort(result.begin(), result.end(), naturalSortGreaterThanCI); + for (modeIndex = 0; modeIndex < modes; modeIndex++) + { + if (SDL_GetDisplayMode(screen, modeIndex, &mode) < 0) + { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error receiving resolutions")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
SDL_GetDisplayMode failed:

") + QString::fromStdString(SDL_GetError()) + "
"); + msgBox.exec(); + return result; + } + QString aspect = getAspect(mode.w, mode.h); + QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h); + + if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { + resolution.append(tr("\t(Wide ") + aspect + ")"); + + } else if (aspect == QLatin1String("4:3")) { + resolution.append(tr("\t(Standard 4:3)")); + } + + result.append(resolution); + } + + result.removeDuplicates(); return result; } +QRect GraphicsPage::getMaximumResolution() +{ + QRect max; + int screens = QApplication::desktop()->screenCount(); + for (int i = 0; i < screens; ++i) + { + QRect res = QApplication::desktop()->screenGeometry(i); + if (res.width() > max.width()) + max.setWidth(res.width()); + if (res.height() > max.height()) + max.setHeight(res.height()); + } + return max; +} + void GraphicsPage::rendererChanged(const QString &renderer) { mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString()); antiAliasingComboBox->clear(); - resolutionComboBox->clear(); antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - resolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); +} + +void GraphicsPage::screenChanged(int screen) +{ + if (screen >= 0) { + resolutionComboBox->clear(); + resolutionComboBox->addItems(getAvailableResolutions(screen)); + } } void GraphicsPage::slotFullScreenChanged(int state) diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index 21039af43..d233ea12e 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -30,10 +30,11 @@ public: GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSettings, QWidget *parent = 0); void saveSettings(); - bool setupOgre(); + bool loadSettings(); public slots: void rendererChanged(const QString &renderer); + void screenChanged(int screen); private slots: void slotFullScreenChanged(int state); @@ -55,10 +56,11 @@ private: GraphicsSettings &mGraphicsSettings; QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer); - QStringList getAvailableResolutions(Ogre::RenderSystem *renderer); - - void loadSettings(); + QStringList getAvailableResolutions(int screen); + QRect getMaximumResolution(); + bool setupOgre(); + bool setupSDL(); }; #endif diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index 09da1d615..dfe2d7413 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,11 +1,23 @@ #include #include #include +#include + +#include #include "maindialog.hpp" +// SDL workaround +#include "graphicspage.hpp" int main(int argc, char *argv[]) { + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + qDebug() << "SDL_Init failed: " << QString::fromStdString(SDL_GetError()); + return 0; + } + QApplication app(argc, argv); // Now we make sure the current dir is set to application path @@ -41,6 +53,8 @@ int main(int argc, char *argv[]) return 0; } - return app.exec(); + int returnValue = app.exec(); + SDL_Quit(); + return returnValue; } diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index e5da3431a..b75d09c51 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -292,8 +292,8 @@ bool MainDialog::setup() // Now create the pages as they need the settings createPages(); - // Call this so we can exit on Ogre errors before mainwindow is shown - if (!mGraphicsPage->setupOgre()) + // Call this so we can exit on Ogre/SDL errors before mainwindow is shown + if (!mGraphicsPage->loadSettings()) return false; loadSettings(); @@ -310,6 +310,8 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous) bool MainDialog::setupLauncherSettings() { + mLauncherSettings.setMultiValueEnabled(true); + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QStringList paths; @@ -427,6 +429,8 @@ bool MainDialog::setupGameSettings() bool MainDialog::setupGraphicsSettings() { + mGraphicsSettings.setMultiValueEnabled(false); + QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); @@ -608,8 +612,21 @@ void MainDialog::closeEvent(QCloseEvent *event) void MainDialog::play() { - if (!writeSettings()) + if (!writeSettings()) { qApp->quit(); + return; + } + + if(!mGameSettings.hasMaster()) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("No master file selected")); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
You do not have any master files selected.

\ + OpenMW will not start without a master file selected.
")); + msgBox.exec(); + return; + } // Launch the game detached startProgram(QString("openmw"), true); diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 9a9b8df41..205879bc3 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include @@ -103,8 +101,8 @@ bool GameSettings::readFile(QTextStream &stream) if (keyRe.indexIn(line) != -1) { - QString key = keyRe.cap(1); - QString value = keyRe.cap(2); + QString key = keyRe.cap(1).trimmed(); + QString value = keyRe.cap(2).trimmed(); // Don't remove existing data entries if (key != QLatin1String("data")) diff --git a/apps/launcher/settings/gamesettings.hpp b/apps/launcher/settings/gamesettings.hpp index 7a17ef9af..55b2107e2 100644 --- a/apps/launcher/settings/gamesettings.hpp +++ b/apps/launcher/settings/gamesettings.hpp @@ -43,6 +43,7 @@ public: inline QStringList getDataDirs() { return mDataDirs; } inline void addDataDir(const QString &dir) { if(!dir.isEmpty()) mDataDirs.append(dir); } inline QString getDataLocal() {return mDataLocal; } + inline bool hasMaster() { return mSettings.count(QString("master")) > 0; } QStringList values(const QString &key, const QStringList &defaultValues = QStringList()); bool readFile(QTextStream &stream); diff --git a/apps/launcher/settings/settingsbase.hpp b/apps/launcher/settings/settingsbase.hpp index 21029b3ad..ed8ada56c 100644 --- a/apps/launcher/settings/settingsbase.hpp +++ b/apps/launcher/settings/settingsbase.hpp @@ -7,14 +7,12 @@ #include #include -#include - template class SettingsBase { public: - SettingsBase() {} + SettingsBase() { mMultiValue = false; } ~SettingsBase() {} inline QString value(const QString &key, const QString &defaultValue = QString()) @@ -36,6 +34,11 @@ public: mSettings.insertMulti(key, value); } + inline void setMultiValueEnabled(bool enable) + { + mMultiValue = enable; + } + inline void remove(const QString &key) { mSettings.remove(key); @@ -66,8 +69,8 @@ public: if (keyRe.indexIn(line) != -1) { - QString key = keyRe.cap(1); - QString value = keyRe.cap(2); + QString key = keyRe.cap(1).trimmed(); + QString value = keyRe.cap(2).trimmed(); if (!sectionPrefix.isEmpty()) key.prepend(sectionPrefix); @@ -75,8 +78,13 @@ public: mSettings.remove(key); QStringList values = mCache.values(key); + if (!values.contains(value)) { - mCache.insertMulti(key, value); + if (mMultiValue) { + mCache.insertMulti(key, value); + } else { + mCache.insert(key, value); + } } } } @@ -94,6 +102,8 @@ public: private: Map mSettings; Map mCache; + + bool mMultiValue; }; #endif // SETTINGSBASE_HPP diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index fc9ce417c..d5d6a3c84 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -645,7 +645,7 @@ std::string MwIniImporter::numberToString(int n) { return str.str(); } -MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) { +MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filename) const { std::cout << "load ini file: " << filename << std::endl; std::string section(""); @@ -701,7 +701,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(std::string filename) { return map; } -MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) { +MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filename) { std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; @@ -738,12 +738,11 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(std::string filename) { return map; } -void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) { - multistrmap::iterator cfgIt; - multistrmap::iterator iniIt; - for(strmap::iterator it=mMergeMap.begin(); it!=mMergeMap.end(); ++it) { +void MwIniImporter::merge(multistrmap &cfg, const multistrmap &ini) const { + multistrmap::const_iterator iniIt; + for(strmap::const_iterator it=mMergeMap.begin(); it!=mMergeMap.end(); ++it) { if((iniIt = ini.find(it->second)) != ini.end()) { - for(std::vector::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) { + for(std::vector::const_iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) { cfg.erase(it->first); insertMultistrmap(cfg, it->first, *vc); } @@ -751,14 +750,13 @@ void MwIniImporter::merge(multistrmap &cfg, multistrmap &ini) { } } -void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) { +void MwIniImporter::mergeFallback(multistrmap &cfg, const multistrmap &ini) const { cfg.erase("fallback"); - multistrmap::iterator cfgIt; - multistrmap::iterator iniIt; - for(std::vector::iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); ++it) { + multistrmap::const_iterator iniIt; + for(std::vector::const_iterator it=mMergeFallback.begin(); it!=mMergeFallback.end(); ++it) { if((iniIt = ini.find(*it)) != ini.end()) { - for(std::vector::iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) { + for(std::vector::const_iterator vc = iniIt->second.begin(); vc != iniIt->second.end(); ++vc) { std::string value(*it); std::replace( value.begin(), value.end(), ' ', '_' ); std::replace( value.begin(), value.end(), ':', '_' ); @@ -769,21 +767,21 @@ void MwIniImporter::mergeFallback(multistrmap &cfg, multistrmap &ini) { } } -void MwIniImporter::insertMultistrmap(multistrmap &cfg, std::string key, std::string value) { - multistrmap::iterator it = cfg.find(key); +void MwIniImporter::insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value) { + const multistrmap::const_iterator it = cfg.find(key); if(it == cfg.end()) { cfg.insert(std::make_pair (key, std::vector() )); } cfg[key].push_back(value); } -void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) { +void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) const { std::vector archives; std::string baseArchive("Archives:Archive "); std::string archive; // Search archives listed in ini file - multistrmap::iterator it = ini.begin(); + multistrmap::const_iterator it = ini.begin(); for(int i=0; it != ini.end(); i++) { archive = baseArchive; archive.append(this->numberToString(i)); @@ -793,7 +791,7 @@ void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) { break; } - for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { + for(std::vector::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { archives.push_back(*entry); } } @@ -805,18 +803,18 @@ void MwIniImporter::importArchives(multistrmap &cfg, multistrmap &ini) { // does not appears in the ini file cfg["fallback-archive"].push_back("Morrowind.bsa"); - for(std::vector::iterator it=archives.begin(); it!=archives.end(); ++it) { + for(std::vector::const_iterator it=archives.begin(); it!=archives.end(); ++it) { cfg["fallback-archive"].push_back(*it); } } -void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { +void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) const { std::vector esmFiles; std::vector espFiles; std::string baseGameFile("Game Files:GameFile"); std::string gameFile(""); - multistrmap::iterator it = ini.begin(); + multistrmap::const_iterator it = ini.begin(); for(int i=0; it != ini.end(); i++) { gameFile = baseGameFile; gameFile.append(this->numberToString(i)); @@ -826,7 +824,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { break; } - for(std::vector::iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { + for(std::vector::const_iterator entry = it->second.begin(); entry!=it->second.end(); ++entry) { std::string filetype(entry->substr(entry->length()-3)); Misc::StringUtils::toLower(filetype); @@ -844,22 +842,22 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, multistrmap &ini) { cfg.erase("master"); cfg.insert( std::make_pair > ("master", std::vector() ) ); - for(std::vector::iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) { + for(std::vector::const_iterator it=esmFiles.begin(); it!=esmFiles.end(); ++it) { cfg["master"].push_back(*it); } cfg.erase("plugin"); cfg.insert( std::make_pair > ("plugin", std::vector() ) ); - for(std::vector::iterator it=espFiles.begin(); it!=espFiles.end(); ++it) { + for(std::vector::const_iterator it=espFiles.begin(); it!=espFiles.end(); ++it) { cfg["plugin"].push_back(*it); } } -void MwIniImporter::writeToFile(boost::iostreams::stream &out, multistrmap &cfg) { +void MwIniImporter::writeToFile(boost::iostreams::stream &out, const multistrmap &cfg) { - for(multistrmap::iterator it=cfg.begin(); it != cfg.end(); ++it) { - for(std::vector::iterator entry=it->second.begin(); entry != it->second.end(); ++entry) { + for(multistrmap::const_iterator it=cfg.begin(); it != cfg.end(); ++it) { + for(std::vector::const_iterator entry=it->second.begin(); entry != it->second.end(); ++entry) { out << (it->first) << "=" << (*entry) << std::endl; } } diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 6b99810bc..784980e09 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -18,18 +18,17 @@ class MwIniImporter { MwIniImporter(); void setInputEncoding(const ToUTF8::FromType& encoding); void setVerbose(bool verbose); - multistrmap loadIniFile(std::string filename); - multistrmap loadCfgFile(std::string filename); - void merge(multistrmap &cfg, multistrmap &ini); - void mergeFallback(multistrmap &cfg, multistrmap &ini); - void importGameFiles(multistrmap &cfg, multistrmap &ini); - void importArchives(multistrmap &cfg, multistrmap &ini); - void writeToFile(boost::iostreams::stream &out, multistrmap &cfg); - + multistrmap loadIniFile(const std::string& filename) const; + static multistrmap loadCfgFile(const std::string& filename); + void merge(multistrmap &cfg, const multistrmap &ini) const; + void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; + void importGameFiles(multistrmap &cfg, const multistrmap &ini) const; + void importArchives(multistrmap &cfg, const multistrmap &ini) const; + static void writeToFile(boost::iostreams::stream &out, const multistrmap &cfg); + private: - void insertMultistrmap(multistrmap &cfg, std::string key, std::string value); - std::string numberToString(int n); - std::string toUTF8(const std::string &str); + static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); + static std::string numberToString(int n); bool mVerbose; strmap mMergeMap; std::vector mMergeFallback; diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index c9d88c0bb..364a6b1a4 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -28,12 +28,26 @@ int main(int argc, char *argv[]) { p_desc.add("ini", 1).add("cfg", 1); bpo::variables_map vm; - bpo::parsed_options parsed = bpo::command_line_parser(argc, argv) - .options(desc) - .positional(p_desc) - .run(); - bpo::store(parsed, vm); + try + { + bpo::parsed_options parsed = bpo::command_line_parser(argc, argv) + .options(desc) + .positional(p_desc) + .run(); + + bpo::store(parsed, vm); + } + catch(boost::program_options::unknown_option & x) + { + std::cerr << "ERROR: " << x.what() << std::endl; + return false; + } + catch(boost::program_options::invalid_command_line_syntax & x) + { + std::cerr << "ERROR: " << x.what() << std::endl; + return false; + } if(vm.count("help") || !vm.count("ini") || !vm.count("cfg")) { std::cout << desc; @@ -55,10 +69,8 @@ int main(int argc, char *argv[]) { std::cerr << "ini file does not exist" << std::endl; return -3; } - if(!boost::filesystem::exists(cfgFile)) { + if(!boost::filesystem::exists(cfgFile)) std::cerr << "cfg file does not exist" << std::endl; - return -4; - } MwIniImporter importer; importer.setVerbose(vm.count("verbose")); diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 3943758c6..cec3756a3 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -57,11 +57,11 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world - table tablesubview scriptsubview + table tablesubview scriptsubview util ) opencs_units_noqt (view/world - dialoguesubview util subviews enumdelegate vartypedelegate scripthighlighter + dialoguesubview subviews enumdelegate vartypedelegate scripthighlighter recordstatusdelegate ) @@ -79,6 +79,7 @@ opencs_units (view/settings abstractwidget usersettingsdialog editorpage + windowpage ) opencs_units_noqt (view/settings diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 8dc5366a9..082fa376c 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -61,6 +61,11 @@ void CS::Editor::setupDataFiles() QString path = QString::fromStdString(iter->string()); mFileDialog.addFiles(path); } + + //load the settings into the userSettings instance. + const QString settingFileName = "opencs.cfg"; + CSMSettings::UserSettings::instance().loadSettings(settingFileName); + } void CS::Editor::createDocument() diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 1c4bcb1ee..380e434c2 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -10,6 +10,7 @@ #include "view/doc/viewmanager.hpp" #include "view/doc/startup.hpp" #include "view/doc/filedialog.hpp" +#include "model/settings/usersettings.hpp" namespace CS { @@ -17,6 +18,7 @@ namespace CS { Q_OBJECT + CSMSettings::UserSettings mUserSettings; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7a66487fb..30e9c21d1 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -1,9 +1,6 @@ - #include "document.hpp" - #include -#include void CSMDoc::Document::load (const std::vector::const_iterator& begin, const std::vector::const_iterator& end, bool lastAsModified) { @@ -21,6 +18,1927 @@ void CSMDoc::Document::load (const std::vector::const_i getData().loadFile (*end2, false); } +void CSMDoc::Document::addGmsts() +{ + static const char *gmstFloats[] = + { + "fAIFleeFleeMult", + "fAIFleeHealthMult", + "fAIMagicSpellMult", + "fAIMeleeArmorMult", + "fAIMeleeSummWeaponMult", + "fAIMeleeWeaponMult", + "fAIRangeMagicSpellMult", + "fAIRangeMeleeWeaponMult", + "fAlarmRadius", + "fAthleticsRunBonus", + "fAudioDefaultMaxDistance", + "fAudioDefaultMinDistance", + "fAudioMaxDistanceMult", + "fAudioMinDistanceMult", + "fAudioVoiceDefaultMaxDistance", + "fAudioVoiceDefaultMinDistance", + "fAutoPCSpellChance", + "fAutoSpellChance", + "fBargainOfferBase", + "fBargainOfferMulti", + "fBarterGoldResetDelay", + "fBaseRunMultiplier", + "fBlockStillBonus", + "fBribe1000Mod", + "fBribe100Mod", + "fBribe10Mod", + "fCombatAngleXY", + "fCombatAngleZ", + "fCombatArmorMinMult", + "fCombatBlockLeftAngle", + "fCombatBlockRightAngle", + "fCombatCriticalStrikeMult", + "fCombatDelayCreature", + "fCombatDelayNPC", + "fCombatDistance", + "fCombatDistanceWerewolfMod", + "fCombatForceSideAngle", + "fCombatInvisoMult", + "fCombatKODamageMult", + "fCombatTorsoSideAngle", + "fCombatTorsoStartPercent", + "fCombatTorsoStopPercent", + "fConstantEffectMult", + "fCorpseClearDelay", + "fCorpseRespawnDelay", + "fCrimeGoldDiscountMult", + "fCrimeGoldTurnInMult", + "fCrimeStealing", + "fDamageStrengthBase", + "fDamageStrengthMult", + "fDifficultyMult", + "fDiseaseXferChance", + "fDispAttacking", + "fDispBargainFailMod", + "fDispBargainSuccessMod", + "fDispCrimeMod", + "fDispDiseaseMod", + "fDispFactionMod", + "fDispFactionRankBase", + "fDispFactionRankMult", + "fDispositionMod", + "fDispPersonalityBase", + "fDispPersonalityMult", + "fDispPickPocketMod", + "fDispRaceMod", + "fDispStealing", + "fDispWeaponDrawn", + "fEffectCostMult", + "fElementalShieldMult", + "fEnchantmentChanceMult", + "fEnchantmentConstantChanceMult", + "fEnchantmentConstantDurationMult", + "fEnchantmentMult", + "fEnchantmentValueMult", + "fEncumberedMoveEffect", + "fEncumbranceStrMult", + "fEndFatigueMult", + "fFallAcroBase", + "fFallAcroMult", + "fFallDamageDistanceMin", + "fFallDistanceBase", + "fFallDistanceMult", + "fFatigueAttackBase", + "fFatigueAttackMult", + "fFatigueBase", + "fFatigueBlockBase", + "fFatigueBlockMult", + "fFatigueJumpBase", + "fFatigueJumpMult", + "fFatigueMult", + "fFatigueReturnBase", + "fFatigueReturnMult", + "fFatigueRunBase", + "fFatigueRunMult", + "fFatigueSneakBase", + "fFatigueSneakMult", + "fFatigueSpellBase", + "fFatigueSpellCostMult", + "fFatigueSpellMult", + "fFatigueSwimRunBase", + "fFatigueSwimRunMult", + "fFatigueSwimWalkBase", + "fFatigueSwimWalkMult", + "fFightDispMult", + "fFightDistanceMultiplier", + "fFightStealing", + "fFleeDistance", + "fGreetDistanceReset", + "fHandtoHandHealthPer", + "fHandToHandReach", + "fHoldBreathEndMult", + "fHoldBreathTime", + "fIdleChanceMultiplier", + "fIngredientMult", + "fInteriorHeadTrackMult", + "fJumpAcrobaticsBase", + "fJumpAcroMultiplier", + "fJumpEncumbranceBase", + "fJumpEncumbranceMultiplier", + "fJumpMoveBase", + "fJumpMoveMult", + "fJumpRunMultiplier", + "fKnockDownMult", + "fLevelMod", + "fLevelUpHealthEndMult", + "fLightMaxMod", + "fLuckMod", + "fMagesGuildTravel", + "fMagicCreatureCastDelay", + "fMagicDetectRefreshRate", + "fMagicItemConstantMult", + "fMagicItemCostMult", + "fMagicItemOnceMult", + "fMagicItemPriceMult", + "fMagicItemRechargePerSecond", + "fMagicItemStrikeMult", + "fMagicItemUsedMult", + "fMagicStartIconBlink", + "fMagicSunBlockedMult", + "fMajorSkillBonus", + "fMaxFlySpeed", + "fMaxHandToHandMult", + "fMaxHeadTrackDistance", + "fMaxWalkSpeed", + "fMaxWalkSpeedCreature", + "fMedMaxMod", + "fMessageTimePerChar", + "fMinFlySpeed", + "fMinHandToHandMult", + "fMinorSkillBonus", + "fMinWalkSpeed", + "fMinWalkSpeedCreature", + "fMiscSkillBonus", + "fNPCbaseMagickaMult", + "fNPCHealthBarFade", + "fNPCHealthBarTime", + "fPCbaseMagickaMult", + "fPerDieRollMult", + "fPersonalityMod", + "fPerTempMult", + "fPickLockMult", + "fPickPocketMod", + "fPotionMinUsefulDuration", + "fPotionStrengthMult", + "fPotionT1DurMult", + "fPotionT1MagMult", + "fPotionT4BaseStrengthMult", + "fPotionT4EquipStrengthMult", + "fProjectileMaxSpeed", + "fProjectileMinSpeed", + "fProjectileThrownStoreChance", + "fRepairAmountMult", + "fRepairMult", + "fReputationMod", + "fRestMagicMult", + "fSeriousWoundMult", + "fSleepRandMod", + "fSleepRestMod", + "fSneakBootMult", + "fSneakDistanceBase", + "fSneakDistanceMultiplier", + "fSneakNoViewMult", + "fSneakSkillMult", + "fSneakSpeedMultiplier", + "fSneakUseDelay", + "fSneakUseDist", + "fSneakViewMult", + "fSoulGemMult", + "fSpecialSkillBonus", + "fSpellMakingValueMult", + "fSpellPriceMult", + "fSpellValueMult", + "fStromWalkMult", + "fStromWindSpeed", + "fSuffocationDamage", + "fSwimHeightScale", + "fSwimRunAthleticsMult", + "fSwimRunBase", + "fSwimWalkAthleticsMult", + "fSwimWalkBase", + "fSwingBlockBase", + "fSwingBlockMult", + "fTargetSpellMaxSpeed", + "fThrownWeaponMaxSpeed", + "fThrownWeaponMinSpeed", + "fTrapCostMult", + "fTravelMult", + "fTravelTimeMult", + "fUnarmoredBase1", + "fUnarmoredBase2", + "fVanityDelay", + "fVoiceIdleOdds", + "fWaterReflectUpdateAlways", + "fWaterReflectUpdateSeldom", + "fWeaponDamageMult", + "fWeaponFatigueBlockMult", + "fWeaponFatigueMult", + "fWereWolfAcrobatics", + "fWereWolfAgility", + "fWereWolfAlchemy", + "fWereWolfAlteration", + "fWereWolfArmorer", + "fWereWolfAthletics", + "fWereWolfAxe", + "fWereWolfBlock", + "fWereWolfBluntWeapon", + "fWereWolfConjuration", + "fWereWolfDestruction", + "fWereWolfEnchant", + "fWereWolfEndurance", + "fWereWolfFatigue", + "fWereWolfHandtoHand", + "fWereWolfHealth", + "fWereWolfHeavyArmor", + "fWereWolfIllusion", + "fWereWolfIntellegence", + "fWereWolfLightArmor", + "fWereWolfLongBlade", + "fWereWolfLuck", + "fWereWolfMagicka", + "fWereWolfMarksman", + "fWereWolfMediumArmor", + "fWereWolfMerchantile", + "fWereWolfMysticism", + "fWereWolfPersonality", + "fWereWolfRestoration", + "fWereWolfRunMult", + "fWereWolfSecurity", + "fWereWolfShortBlade", + "fWereWolfSilverWeaponDamageMult", + "fWereWolfSneak", + "fWereWolfSpear", + "fWereWolfSpeechcraft", + "fWereWolfSpeed", + "fWereWolfStrength", + "fWereWolfUnarmored", + "fWereWolfWillPower", + "fWortChanceValue", + 0 + }; + + static const float gmstFloatsValues[] = + { + 0.3, // fAIFleeFleeMult + 7.0, // fAIFleeHealthMult + 3.0, // fAIMagicSpellMult + 1.0, // fAIMeleeArmorMult + 1.0, // fAIMeleeSummWeaponMult + 2.0, // fAIMeleeWeaponMult + 5.0, // fAIRangeMagicSpellMult + 5.0, // fAIRangeMeleeWeaponMult + 2000.0, // fAlarmRadius + 1.0, // fAthleticsRunBonus + 40.0, // fAudioDefaultMaxDistance + 5.0, // fAudioDefaultMinDistance + 50.0, // fAudioMaxDistanceMult + 20.0, // fAudioMinDistanceMult + 60.0, // fAudioVoiceDefaultMaxDistance + 10.0, // fAudioVoiceDefaultMinDistance + 50.0, // fAutoPCSpellChance + 80.0, // fAutoSpellChance + 50.0, // fBargainOfferBase + -4.0, // fBargainOfferMulti + 24.0, // fBarterGoldResetDelay + 1.75, // fBaseRunMultiplier + 1.25, // fBlockStillBonus + 150.0, // fBribe1000Mod + 75.0, // fBribe100Mod + 35.0, // fBribe10Mod + 60.0, // fCombatAngleXY + 60.0, // fCombatAngleZ + 0.25, // fCombatArmorMinMult + -90.0, // fCombatBlockLeftAngle + 30.0, // fCombatBlockRightAngle + 4.0, // fCombatCriticalStrikeMult + 0.1, // fCombatDelayCreature + 0.1, // fCombatDelayNPC + 128.0, // fCombatDistance + 0.3, // fCombatDistanceWerewolfMod + 30.0, // fCombatForceSideAngle + 0.2, // fCombatInvisoMult + 1.5, // fCombatKODamageMult + 45.0, // fCombatTorsoSideAngle + 0.3, // fCombatTorsoStartPercent + 0.8, // fCombatTorsoStopPercent + 15.0, // fConstantEffectMult + 72.0, // fCorpseClearDelay + 72.0, // fCorpseRespawnDelay + 0.5, // fCrimeGoldDiscountMult + 0.9, // fCrimeGoldTurnInMult + 1.0, // fCrimeStealing + 0.5, // fDamageStrengthBase + 0.1, // fDamageStrengthMult + 5.0, // fDifficultyMult + 2.5, // fDiseaseXferChance + -10.0, // fDispAttacking + -1.0, // fDispBargainFailMod + 1.0, // fDispBargainSuccessMod + 0.0, // fDispCrimeMod + -10.0, // fDispDiseaseMod + 3.0, // fDispFactionMod + 1.0, // fDispFactionRankBase + 0.5, // fDispFactionRankMult + 1.0, // fDispositionMod + 50.0, // fDispPersonalityBase + 0.5, // fDispPersonalityMult + -25.0, // fDispPickPocketMod + 5.0, // fDispRaceMod + -0.5, // fDispStealing + -5.0, // fDispWeaponDrawn + 0.5, // fEffectCostMult + 0.1, // fElementalShieldMult + 3.0, // fEnchantmentChanceMult + 0.5, // fEnchantmentConstantChanceMult + 100.0, // fEnchantmentConstantDurationMult + 0.1, // fEnchantmentMult + 1000.0, // fEnchantmentValueMult + 0.3, // fEncumberedMoveEffect + 5.0, // fEncumbranceStrMult + 0.04, // fEndFatigueMult + 0.25, // fFallAcroBase + 0.01, // fFallAcroMult + 400.0, // fFallDamageDistanceMin + 0.0, // fFallDistanceBase + 0.07, // fFallDistanceMult + 2.0, // fFatigueAttackBase + 0.0, // fFatigueAttackMult + 1.25, // fFatigueBase + 4.0, // fFatigueBlockBase + 0.0, // fFatigueBlockMult + 5.0, // fFatigueJumpBase + 0.0, // fFatigueJumpMult + 0.5, // fFatigueMult + 2.5, // fFatigueReturnBase + 0.02, // fFatigueReturnMult + 5.0, // fFatigueRunBase + 2.0, // fFatigueRunMult + 1.5, // fFatigueSneakBase + 1.5, // fFatigueSneakMult + 0.0, // fFatigueSpellBase + 0.0, // fFatigueSpellCostMult + 0.0, // fFatigueSpellMult + 7.0, // fFatigueSwimRunBase + 0.0, // fFatigueSwimRunMult + 2.5, // fFatigueSwimWalkBase + 0.0, // fFatigueSwimWalkMult + 0.2, // fFightDispMult + 0.005, // fFightDistanceMultiplier + 50.0, // fFightStealing + 3000.0, // fFleeDistance + 512.0, // fGreetDistanceReset + 0.1, // fHandtoHandHealthPer + 1.0, // fHandToHandReach + 0.5, // fHoldBreathEndMult + 20.0, // fHoldBreathTime + 0.75, // fIdleChanceMultiplier + 1.0, // fIngredientMult + 0.5, // fInteriorHeadTrackMult + 128.0, // fJumpAcrobaticsBase + 4.0, // fJumpAcroMultiplier + 0.5, // fJumpEncumbranceBase + 1.0, // fJumpEncumbranceMultiplier + 0.5, // fJumpMoveBase + 0.5, // fJumpMoveMult + 1.0, // fJumpRunMultiplier + 0.5, // fKnockDownMult + 5.0, // fLevelMod + 0.1, // fLevelUpHealthEndMult + 0.6, // fLightMaxMod + 10.0, // fLuckMod + 10.0, // fMagesGuildTravel + 1.5, // fMagicCreatureCastDelay + 0.0167, // fMagicDetectRefreshRate + 1.0, // fMagicItemConstantMult + 1.0, // fMagicItemCostMult + 1.0, // fMagicItemOnceMult + 1.0, // fMagicItemPriceMult + 0.05, // fMagicItemRechargePerSecond + 1.0, // fMagicItemStrikeMult + 1.0, // fMagicItemUsedMult + 3.0, // fMagicStartIconBlink + 0.5, // fMagicSunBlockedMult + 0.75, // fMajorSkillBonus + 300.0, // fMaxFlySpeed + 0.5, // fMaxHandToHandMult + 400.0, // fMaxHeadTrackDistance + 200.0, // fMaxWalkSpeed + 300.0, // fMaxWalkSpeedCreature + 0.9, // fMedMaxMod + 0.1, // fMessageTimePerChar + 5.0, // fMinFlySpeed + 0.1, // fMinHandToHandMult + 1.0, // fMinorSkillBonus + 100.0, // fMinWalkSpeed + 5.0, // fMinWalkSpeedCreature + 1.25, // fMiscSkillBonus + 2.0, // fNPCbaseMagickaMult + 0.5, // fNPCHealthBarFade + 3.0, // fNPCHealthBarTime + 1.0, // fPCbaseMagickaMult + 0.3, // fPerDieRollMult + 5.0, // fPersonalityMod + 1.0, // fPerTempMult + -1.0, // fPickLockMult + 0.3, // fPickPocketMod + 20.0, // fPotionMinUsefulDuration + 0.5, // fPotionStrengthMult + 0.5, // fPotionT1DurMult + 1.5, // fPotionT1MagMult + 20.0, // fPotionT4BaseStrengthMult + 12.0, // fPotionT4EquipStrengthMult + 3000.0, // fProjectileMaxSpeed + 400.0, // fProjectileMinSpeed + 25.0, // fProjectileThrownStoreChance + 3.0, // fRepairAmountMult + 1.0, // fRepairMult + 1.0, // fReputationMod + 0.15, // fRestMagicMult + 0.0, // fSeriousWoundMult + 0.25, // fSleepRandMod + 0.3, // fSleepRestMod + -1.0, // fSneakBootMult + 0.5, // fSneakDistanceBase + 0.002, // fSneakDistanceMultiplier + 0.5, // fSneakNoViewMult + 1.0, // fSneakSkillMult + 0.75, // fSneakSpeedMultiplier + 1.0, // fSneakUseDelay + 500.0, // fSneakUseDist + 1.5, // fSneakViewMult + 3.0, // fSoulGemMult + 0.8, // fSpecialSkillBonus + 7.0, // fSpellMakingValueMult + 2.0, // fSpellPriceMult + 10.0, // fSpellValueMult + 0.25, // fStromWalkMult + 0.7, // fStromWindSpeed + 3.0, // fSuffocationDamage + 0.9, // fSwimHeightScale + 0.1, // fSwimRunAthleticsMult + 0.5, // fSwimRunBase + 0.02, // fSwimWalkAthleticsMult + 0.5, // fSwimWalkBase + 1.0, // fSwingBlockBase + 1.0, // fSwingBlockMult + 1000.0, // fTargetSpellMaxSpeed + 1000.0, // fThrownWeaponMaxSpeed + 300.0, // fThrownWeaponMinSpeed + 0.0, // fTrapCostMult + 4000.0, // fTravelMult + 16000.0,// fTravelTimeMult + 0.1, // fUnarmoredBase1 + 0.065, // fUnarmoredBase2 + 30.0, // fVanityDelay + 10.0, // fVoiceIdleOdds + 0.0, // fWaterReflectUpdateAlways + 10.0, // fWaterReflectUpdateSeldom + 0.1, // fWeaponDamageMult + 1.0, // fWeaponFatigueBlockMult + 0.25, // fWeaponFatigueMult + 150.0, // fWereWolfAcrobatics + 150.0, // fWereWolfAgility + 1.0, // fWereWolfAlchemy + 1.0, // fWereWolfAlteration + 1.0, // fWereWolfArmorer + 150.0, // fWereWolfAthletics + 1.0, // fWereWolfAxe + 1.0, // fWereWolfBlock + 1.0, // fWereWolfBluntWeapon + 1.0, // fWereWolfConjuration + 1.0, // fWereWolfDestruction + 1.0, // fWereWolfEnchant + 150.0, // fWereWolfEndurance + 400.0, // fWereWolfFatigue + 100.0, // fWereWolfHandtoHand + 2.0, // fWereWolfHealth + 1.0, // fWereWolfHeavyArmor + 1.0, // fWereWolfIllusion + 1.0, // fWereWolfIntellegence + 1.0, // fWereWolfLightArmor + 1.0, // fWereWolfLongBlade + 1.0, // fWereWolfLuck + 100.0, // fWereWolfMagicka + 1.0, // fWereWolfMarksman + 1.0, // fWereWolfMediumArmor + 1.0, // fWereWolfMerchantile + 1.0, // fWereWolfMysticism + 1.0, // fWereWolfPersonality + 1.0, // fWereWolfRestoration + 1.5, // fWereWolfRunMult + 1.0, // fWereWolfSecurity + 1.0, // fWereWolfShortBlade + 1.5, // fWereWolfSilverWeaponDamageMult + 1.0, // fWereWolfSneak + 1.0, // fWereWolfSpear + 1.0, // fWereWolfSpeechcraft + 150.0, // fWereWolfSpeed + 150.0, // fWereWolfStrength + 100.0, // fWereWolfUnarmored + 1.0, // fWereWolfWillPower + 15.0, // fWortChanceValue + }; + + static const char *gmstIntegers[] = + { + "i1stPersonSneakDelta", + "iAlarmAttack", + "iAlarmKilling", + "iAlarmPickPocket", + "iAlarmStealing", + "iAlarmTresspass", + "iAlchemyMod", + "iAutoPCSpellMax", + "iAutoRepFacMod", + "iAutoRepLevMod", + "iAutoSpellAlterationMax", + "iAutoSpellAttSkillMin", + "iAutoSpellConjurationMax", + "iAutoSpellDestructionMax", + "iAutoSpellIllusionMax", + "iAutoSpellMysticismMax", + "iAutoSpellRestorationMax", + "iAutoSpellTimesCanCast", + "iBarterFailDisposition", + "iBarterSuccessDisposition", + "iBaseArmorSkill", + "iBlockMaxChance", + "iBlockMinChance", + "iBootsWeight", + "iCrimeAttack", + "iCrimeKilling", + "iCrimePickPocket", + "iCrimeThreshold", + "iCrimeThresholdMultiplier", + "iCrimeTresspass", + "iCuirassWeight", + "iDaysinPrisonMod", + "iDispAttackMod", + "iDispKilling", + "iDispTresspass", + "iFightAlarmMult", + "iFightAttack", + "iFightAttacking", + "iFightDistanceBase", + "iFightKilling", + "iFightPickpocket", + "iFightTrespass", + "iFlee", + "iGauntletWeight", + "iGreavesWeight", + "iGreetDistanceMultiplier", + "iGreetDuration", + "iHelmWeight", + "iKnockDownOddsBase", + "iKnockDownOddsMult", + "iLevelUp01Mult", + "iLevelUp02Mult", + "iLevelUp03Mult", + "iLevelUp04Mult", + "iLevelUp05Mult", + "iLevelUp06Mult", + "iLevelUp07Mult", + "iLevelUp08Mult", + "iLevelUp09Mult", + "iLevelUp10Mult", + "iLevelupMajorMult", + "iLevelupMajorMultAttribute", + "iLevelupMinorMult", + "iLevelupMinorMultAttribute", + "iLevelupMiscMultAttriubte", + "iLevelupSpecialization", + "iLevelupTotal", + "iMagicItemChargeConst", + "iMagicItemChargeOnce", + "iMagicItemChargeStrike", + "iMagicItemChargeUse", + "iMaxActivateDist", + "iMaxInfoDist", + "iMonthsToRespawn", + "iNumberCreatures", + "iPauldronWeight", + "iPerMinChance", + "iPerMinChange", + "iPickMaxChance", + "iPickMinChance", + "iShieldWeight", + "iSoulAmountForConstantEffect", + "iTrainingMod", + "iVoiceAttackOdds", + "iVoiceHitOdds", + "iWereWolfBounty", + "iWereWolfFightMod", + "iWereWolfFleeMod", + "iWereWolfLevelToAttack", + 0 + }; + + static const int gmstIntegersValues[] = + { + 10, // i1stPersonSneakDelta + 50, // iAlarmAttack + 90, // iAlarmKilling + 20, // iAlarmPickPocket + 1, // iAlarmStealing + 5, // iAlarmTresspass + 2, // iAlchemyMod + 100, // iAutoPCSpellMax + 2, // iAutoRepFacMod + 0, // iAutoRepLevMod + 5, // iAutoSpellAlterationMax + 70, // iAutoSpellAttSkillMin + 2, // iAutoSpellConjurationMax + 5, // iAutoSpellDestructionMax + 5, // iAutoSpellIllusionMax + 5, // iAutoSpellMysticismMax + 5, // iAutoSpellRestorationMax + 3, // iAutoSpellTimesCanCast + -1, // iBarterFailDisposition + 1, // iBarterSuccessDisposition + 30, // iBaseArmorSkill + 50, // iBlockMaxChance + 10, // iBlockMinChance + 20, // iBootsWeight + 40, // iCrimeAttack + 1000, // iCrimeKilling + 25, // iCrimePickPocket + 1000, // iCrimeThreshold + 10, // iCrimeThresholdMultiplier + 5, // iCrimeTresspass + 30, // iCuirassWeight + 100, // iDaysinPrisonMod + -50, // iDispAttackMod + -50, // iDispKilling + -20, // iDispTresspass + 1, // iFightAlarmMult + 100, // iFightAttack + 50, // iFightAttacking + 20, // iFightDistanceBase + 50, // iFightKilling + 25, // iFightPickpocket + 25, // iFightTrespass + 0, // iFlee + 5, // iGauntletWeight + 15, // iGreavesWeight + 6, // iGreetDistanceMultiplier + 4, // iGreetDuration + 5, // iHelmWeight + 50, // iKnockDownOddsBase + 50, // iKnockDownOddsMult + 2, // iLevelUp01Mult + 2, // iLevelUp02Mult + 2, // iLevelUp03Mult + 2, // iLevelUp04Mult + 3, // iLevelUp05Mult + 3, // iLevelUp06Mult + 3, // iLevelUp07Mult + 4, // iLevelUp08Mult + 4, // iLevelUp09Mult + 5, // iLevelUp10Mult + 1, // iLevelupMajorMult + 1, // iLevelupMajorMultAttribute + 1, // iLevelupMinorMult + 1, // iLevelupMinorMultAttribute + 1, // iLevelupMiscMultAttriubte + 1, // iLevelupSpecialization + 10, // iLevelupTotal + 10, // iMagicItemChargeConst + 1, // iMagicItemChargeOnce + 10, // iMagicItemChargeStrike + 5, // iMagicItemChargeUse + 192, // iMaxActivateDist + 192, // iMaxInfoDist + 4, // iMonthsToRespawn + 1, // iNumberCreatures + 10, // iPauldronWeight + 5, // iPerMinChance + 10, // iPerMinChange + 75, // iPickMaxChance + 5, // iPickMinChance + 15, // iShieldWeight + 400, // iSoulAmountForConstantEffect + 10, // iTrainingMod + 10, // iVoiceAttackOdds + 30, // iVoiceHitOdds + 10000, // iWereWolfBounty + 100, // iWereWolfFightMod + 100, // iWereWolfFleeMod + 20, // iWereWolfLevelToAttack + }; + + static const char *gmstStrings[] = + { + "s3dAudio", + "s3dHardware", + "s3dSoftware", + "sAbsorb", + "sAcrobat", + "sActivate", + "sActivateXbox", + "sActorInCombat", + "sAdmire", + "sAdmireFail", + "sAdmireSuccess", + "sAgent", + "sAgiDesc", + "sAIDistance", + "sAlembic", + "sAllTab", + "sAlways", + "sAlways_Run", + "sand", + "sApparatus", + "sApparelTab", + "sArcher", + "sArea", + "sAreaDes", + "sArmor", + "sArmorRating", + "sAsk", + "sAssassin", + "sAt", + "sAttack", + "sAttributeAgility", + "sAttributeEndurance", + "sAttributeIntelligence", + "sAttributeListTitle", + "sAttributeLuck", + "sAttributePersonality", + "sAttributesMenu1", + "sAttributeSpeed", + "sAttributeStrength", + "sAttributeWillpower", + "sAudio", + "sAuto_Run", + "sBack", + "sBackspace", + "sBackXbox", + "sBarbarian", + "sBard", + "sBarter", + "sBarterDialog1", + "sBarterDialog10", + "sBarterDialog11", + "sBarterDialog12", + "sBarterDialog2", + "sBarterDialog3", + "sBarterDialog4", + "sBarterDialog5", + "sBarterDialog6", + "sBarterDialog7", + "sBarterDialog8", + "sBarterDialog9", + "sBattlemage", + "sBestAttack", + "sBirthSign", + "sBirthsignmenu1", + "sBirthsignmenu2", + "sBlocks", + "sBonusSkillTitle", + "sBookPageOne", + "sBookPageTwo", + "sBookSkillMessage", + "sBounty", + "sBreath", + "sBribe", + "sBribe", + "sBribe", + "sBribeFail", + "sBribeSuccess", + "sBuy", + "sBye", + "sCalcinator", + "sCancel", + "sCantEquipWeapWarning", + "sCastCost", + "sCaughtStealingMessage", + "sCenter", + "sChangedMastersMsg", + "sCharges", + "sChooseClassMenu1", + "sChooseClassMenu2", + "sChooseClassMenu3", + "sChooseClassMenu4", + "sChop", + "sClass", + "sClassChoiceMenu1", + "sClassChoiceMenu2", + "sClassChoiceMenu3", + "sClose", + "sCompanionShare", + "sCompanionWarningButtonOne", + "sCompanionWarningButtonTwo", + "sCompanionWarningMessage", + "sCondition", + "sConsoleTitle", + "sContainer", + "sContentsMessage1", + "sContentsMessage2", + "sContentsMessage3", + "sControlerVibration", + "sControls", + "sControlsMenu1", + "sControlsMenu2", + "sControlsMenu3", + "sControlsMenu4", + "sControlsMenu5", + "sControlsMenu6", + "sCostChance", + "sCostCharge", + "sCreate", + "sCreateClassMenu1", + "sCreateClassMenu2", + "sCreateClassMenu3", + "sCreateClassMenuHelp1", + "sCreateClassMenuHelp2", + "sCreateClassMenuWarning", + "sCreatedEffects", + "sCrimeHelp", + "sCrimeMessage", + "sCrouch_Sneak", + "sCrouchXbox", + "sCrusader", + "sCursorOff", + "sCustom", + "sCustomClassName", + "sDamage", + "sDark_Gamma", + "sDay", + "sDefaultCellname", + "sDelete", + "sDeleteGame", + "sDeleteNote", + "sDeleteSpell", + "sDeleteSpellError", + "sDetail_Level", + "sDialogMenu1", + "sDialogText1Xbox", + "sDialogText2Xbox", + "sDialogText3Xbox", + "sDifficulty", + "sDisposeCorpseFail", + "sDisposeofCorpse", + "sDone", + "sDoYouWantTo", + "sDrain", + "sDrop", + "sDuration", + "sDurationDes", + "sEasy", + "sEditNote", + "sEffectAbsorbAttribute", + "sEffectAbsorbFatigue", + "sEffectAbsorbHealth", + "sEffectAbsorbSkill", + "sEffectAbsorbSpellPoints", + "sEffectAlmsiviIntervention", + "sEffectBlind", + "sEffectBoundBattleAxe", + "sEffectBoundBoots", + "sEffectBoundCuirass", + "sEffectBoundDagger", + "sEffectBoundGloves", + "sEffectBoundHelm", + "sEffectBoundLongbow", + "sEffectBoundLongsword", + "sEffectBoundMace", + "sEffectBoundShield", + "sEffectBoundSpear", + "sEffectBurden", + "sEffectCalmCreature", + "sEffectCalmHumanoid", + "sEffectChameleon", + "sEffectCharm", + "sEffectCommandCreatures", + "sEffectCommandHumanoids", + "sEffectCorpus", + "sEffectCureBlightDisease", + "sEffectCureCommonDisease", + "sEffectCureCorprusDisease", + "sEffectCureParalyzation", + "sEffectCurePoison", + "sEffectDamageAttribute", + "sEffectDamageFatigue", + "sEffectDamageHealth", + "sEffectDamageMagicka", + "sEffectDamageSkill", + "sEffectDemoralizeCreature", + "sEffectDemoralizeHumanoid", + "sEffectDetectAnimal", + "sEffectDetectEnchantment", + "sEffectDetectKey", + "sEffectDisintegrateArmor", + "sEffectDisintegrateWeapon", + "sEffectDispel", + "sEffectDivineIntervention", + "sEffectDrainAttribute", + "sEffectDrainFatigue", + "sEffectDrainHealth", + "sEffectDrainSkill", + "sEffectDrainSpellpoints", + "sEffectExtraSpell", + "sEffectFeather", + "sEffectFireDamage", + "sEffectFireShield", + "sEffectFortifyAttackBonus", + "sEffectFortifyAttribute", + "sEffectFortifyFatigue", + "sEffectFortifyHealth", + "sEffectFortifyMagickaMultiplier", + "sEffectFortifySkill", + "sEffectFortifySpellpoints", + "sEffectFrenzyCreature", + "sEffectFrenzyHumanoid", + "sEffectFrostDamage", + "sEffectFrostShield", + "sEffectInvisibility", + "sEffectJump", + "sEffectLevitate", + "sEffectLight", + "sEffectLightningShield", + "sEffectLock", + "sEffectMark", + "sEffectNightEye", + "sEffectOpen", + "sEffectParalyze", + "sEffectPoison", + "sEffectRallyCreature", + "sEffectRallyHumanoid", + "sEffectRecall", + "sEffectReflect", + "sEffectRemoveCurse", + "sEffectResistBlightDisease", + "sEffectResistCommonDisease", + "sEffectResistCorprusDisease", + "sEffectResistFire", + "sEffectResistFrost", + "sEffectResistMagicka", + "sEffectResistNormalWeapons", + "sEffectResistParalysis", + "sEffectResistPoison", + "sEffectResistShock", + "sEffectRestoreAttribute", + "sEffectRestoreFatigue", + "sEffectRestoreHealth", + "sEffectRestoreSkill", + "sEffectRestoreSpellPoints", + "sEffects", + "sEffectSanctuary", + "sEffectShield", + "sEffectShockDamage", + "sEffectSilence", + "sEffectSlowFall", + "sEffectSoultrap", + "sEffectSound", + "sEffectSpellAbsorption", + "sEffectStuntedMagicka", + "sEffectSummonAncestralGhost", + "sEffectSummonBonelord", + "sEffectSummonCenturionSphere", + "sEffectSummonClannfear", + "sEffectSummonCreature01", + "sEffectSummonCreature02", + "sEffectSummonCreature03", + "sEffectSummonCreature04", + "sEffectSummonCreature05", + "sEffectSummonDaedroth", + "sEffectSummonDremora", + "sEffectSummonFabricant", + "sEffectSummonFlameAtronach", + "sEffectSummonFrostAtronach", + "sEffectSummonGoldensaint", + "sEffectSummonGreaterBonewalker", + "sEffectSummonHunger", + "sEffectSummonLeastBonewalker", + "sEffectSummonScamp", + "sEffectSummonSkeletalMinion", + "sEffectSummonStormAtronach", + "sEffectSummonWingedTwilight", + "sEffectSunDamage", + "sEffectSwiftSwim", + "sEffectTelekinesis", + "sEffectTurnUndead", + "sEffectVampirism", + "sEffectWaterBreathing", + "sEffectWaterWalking", + "sEffectWeaknessToBlightDisease", + "sEffectWeaknessToCommonDisease", + "sEffectWeaknessToCorprusDisease", + "sEffectWeaknessToFire", + "sEffectWeaknessToFrost", + "sEffectWeaknessToMagicka", + "sEffectWeaknessToNormalWeapons", + "sEffectWeaknessToPoison", + "sEffectWeaknessToShock", + "sEnableJoystick", + "sEnchanting", + "sEnchantItems", + "sEnchantmentHelp1", + "sEnchantmentHelp10", + "sEnchantmentHelp2", + "sEnchantmentHelp3", + "sEnchantmentHelp4", + "sEnchantmentHelp5", + "sEnchantmentHelp6", + "sEnchantmentHelp7", + "sEnchantmentHelp8", + "sEnchantmentHelp9", + "sEnchantmentMenu1", + "sEnchantmentMenu10", + "sEnchantmentMenu11", + "sEnchantmentMenu12", + "sEnchantmentMenu2", + "sEnchantmentMenu3", + "sEnchantmentMenu4", + "sEnchantmentMenu5", + "sEnchantmentMenu6", + "sEnchantmentMenu7", + "sEnchantmentMenu8", + "sEnchantmentMenu9", + "sEncumbrance", + "sEndDesc", + "sEquip", + "sExitGame", + "sExpelled", + "sExpelledMessage", + "sFace", + "sFaction", + "sFar", + "sFast", + "sFatDesc", + "sFatigue", + "sFavoriteSkills", + "sfeet", + "sFileSize", + "sfootarea", + "sFootsteps", + "sfor", + "sFortify", + "sForward", + "sForwardXbox", + "sFull", + "sGame", + "sGameWithoutLauncherXbox", + "sGamma_Correction", + "sGeneralMastPlugMismatchMsg", + "sGold", + "sGoodbye", + "sGoverningAttribute", + "sgp", + "sHair", + "sHard", + "sHeal", + "sHealer", + "sHealth", + "sHealthDesc", + "sHealthPerHourOfRest", + "sHealthPerLevel", + "sHeavy", + "sHigh", + "sin", + "sInfo", + "sInfoRefusal", + "sIngredients", + "sInPrisonTitle", + "sInputMenu1", + "sIntDesc", + "sIntimidate", + "sIntimidateFail", + "sIntimidateSuccess", + "sInvalidSaveGameMsg", + "sInvalidSaveGameMsgXBOX", + "sInventory", + "sInventoryMenu1", + "sInventoryMessage1", + "sInventoryMessage2", + "sInventoryMessage3", + "sInventoryMessage4", + "sInventoryMessage5", + "sInventorySelectNoIngredients", + "sInventorySelectNoItems", + "sInventorySelectNoSoul", + "sItem", + "sItemCastConstant", + "sItemCastOnce", + "sItemCastWhenStrikes", + "sItemCastWhenUsed", + "sItemName", + "sJournal", + "sJournalCmd", + "sJournalEntry", + "sJournalXbox", + "sJoystickHatShort", + "sJoystickNotFound", + "sJoystickShort", + "sJump", + "sJumpXbox", + "sKeyName_00", + "sKeyName_01", + "sKeyName_02", + "sKeyName_03", + "sKeyName_04", + "sKeyName_05", + "sKeyName_06", + "sKeyName_07", + "sKeyName_08", + "sKeyName_09", + "sKeyName_0A", + "sKeyName_0B", + "sKeyName_0C", + "sKeyName_0D", + "sKeyName_0E", + "sKeyName_0F", + "sKeyName_10", + "sKeyName_11", + "sKeyName_12", + "sKeyName_13", + "sKeyName_14", + "sKeyName_15", + "sKeyName_16", + "sKeyName_17", + "sKeyName_18", + "sKeyName_19", + "sKeyName_1A", + "sKeyName_1B", + "sKeyName_1C", + "sKeyName_1D", + "sKeyName_1E", + "sKeyName_1F", + "sKeyName_20", + "sKeyName_21", + "sKeyName_22", + "sKeyName_23", + "sKeyName_24", + "sKeyName_25", + "sKeyName_26", + "sKeyName_27", + "sKeyName_28", + "sKeyName_29", + "sKeyName_2A", + "sKeyName_2B", + "sKeyName_2C", + "sKeyName_2D", + "sKeyName_2E", + "sKeyName_2F", + "sKeyName_30", + "sKeyName_31", + "sKeyName_32", + "sKeyName_33", + "sKeyName_34", + "sKeyName_35", + "sKeyName_36", + "sKeyName_37", + "sKeyName_38", + "sKeyName_39", + "sKeyName_3A", + "sKeyName_3B", + "sKeyName_3C", + "sKeyName_3D", + "sKeyName_3E", + "sKeyName_3F", + "sKeyName_40", + "sKeyName_41", + "sKeyName_42", + "sKeyName_43", + "sKeyName_44", + "sKeyName_45", + "sKeyName_46", + "sKeyName_47", + "sKeyName_48", + "sKeyName_49", + "sKeyName_4A", + "sKeyName_4B", + "sKeyName_4C", + "sKeyName_4D", + "sKeyName_4E", + "sKeyName_4F", + "sKeyName_50", + "sKeyName_51", + "sKeyName_52", + "sKeyName_53", + "sKeyName_54", + "sKeyName_55", + "sKeyName_56", + "sKeyName_57", + "sKeyName_58", + "sKeyName_59", + "sKeyName_5A", + "sKeyName_5B", + "sKeyName_5C", + "sKeyName_5D", + "sKeyName_5E", + "sKeyName_5F", + "sKeyName_60", + "sKeyName_61", + "sKeyName_62", + "sKeyName_63", + "sKeyName_64", + "sKeyName_65", + "sKeyName_66", + "sKeyName_67", + "sKeyName_68", + "sKeyName_69", + "sKeyName_6A", + "sKeyName_6B", + "sKeyName_6C", + "sKeyName_6D", + "sKeyName_6E", + "sKeyName_6F", + "sKeyName_70", + "sKeyName_71", + "sKeyName_72", + "sKeyName_73", + "sKeyName_74", + "sKeyName_75", + "sKeyName_76", + "sKeyName_77", + "sKeyName_78", + "sKeyName_79", + "sKeyName_7A", + "sKeyName_7B", + "sKeyName_7C", + "sKeyName_7D", + "sKeyName_7E", + "sKeyName_7F", + "sKeyName_80", + "sKeyName_81", + "sKeyName_82", + "sKeyName_83", + "sKeyName_84", + "sKeyName_85", + "sKeyName_86", + "sKeyName_87", + "sKeyName_88", + "sKeyName_89", + "sKeyName_8A", + "sKeyName_8B", + "sKeyName_8C", + "sKeyName_8D", + "sKeyName_8E", + "sKeyName_8F", + "sKeyName_90", + "sKeyName_91", + "sKeyName_92", + "sKeyName_93", + "sKeyName_94", + "sKeyName_95", + "sKeyName_96", + "sKeyName_97", + "sKeyName_98", + "sKeyName_99", + "sKeyName_9A", + "sKeyName_9B", + "sKeyName_9C", + "sKeyName_9D", + "sKeyName_9E", + "sKeyName_9F", + "sKeyName_A0", + "sKeyName_A1", + "sKeyName_A2", + "sKeyName_A3", + "sKeyName_A4", + "sKeyName_A5", + "sKeyName_A6", + "sKeyName_A7", + "sKeyName_A8", + "sKeyName_A9", + "sKeyName_AA", + "sKeyName_AB", + "sKeyName_AC", + "sKeyName_AD", + "sKeyName_AE", + "sKeyName_AF", + "sKeyName_B0", + "sKeyName_B1", + "sKeyName_B2", + "sKeyName_B3", + "sKeyName_B4", + "sKeyName_B5", + "sKeyName_B6", + "sKeyName_B7", + "sKeyName_B8", + "sKeyName_B9", + "sKeyName_BA", + "sKeyName_BB", + "sKeyName_BC", + "sKeyName_BD", + "sKeyName_BE", + "sKeyName_BF", + "sKeyName_C0", + "sKeyName_C1", + "sKeyName_C2", + "sKeyName_C3", + "sKeyName_C4", + "sKeyName_C5", + "sKeyName_C6", + "sKeyName_C7", + "sKeyName_C8", + "sKeyName_C9", + "sKeyName_CA", + "sKeyName_CB", + "sKeyName_CC", + "sKeyName_CD", + "sKeyName_CE", + "sKeyName_CF", + "sKeyName_D0", + "sKeyName_D1", + "sKeyName_D2", + "sKeyName_D3", + "sKeyName_D4", + "sKeyName_D5", + "sKeyName_D6", + "sKeyName_D7", + "sKeyName_D8", + "sKeyName_D9", + "sKeyName_DA", + "sKeyName_DB", + "sKeyName_DC", + "sKeyName_DD", + "sKeyName_DE", + "sKeyName_DF", + "sKeyName_E0", + "sKeyName_E1", + "sKeyName_E2", + "sKeyName_E3", + "sKeyName_E4", + "sKeyName_E5", + "sKeyName_E6", + "sKeyName_E7", + "sKeyName_E8", + "sKeyName_E9", + "sKeyName_EA", + "sKeyName_EB", + "sKeyName_EC", + "sKeyName_ED", + "sKeyName_EE", + "sKeyName_EF", + "sKeyName_F0", + "sKeyName_F1", + "sKeyName_F2", + "sKeyName_F3", + "sKeyName_F4", + "sKeyName_F5", + "sKeyName_F6", + "sKeyName_F7", + "sKeyName_F8", + "sKeyName_F9", + "sKeyName_FA", + "sKeyName_FB", + "sKeyName_FC", + "sKeyName_FD", + "sKeyName_FE", + "sKeyName_FF", + "sKeyUsed", + "sKilledEssential", + "sKnight", + "sLeft", + "sLess", + "sLevel", + "sLevelProgress", + "sLevels", + "sLevelUp", + "sLevelUpMenu1", + "sLevelUpMenu2", + "sLevelUpMenu3", + "sLevelUpMenu4", + "sLevelUpMsg", + "sLevitateDisabled", + "sLight", + "sLight_Gamma", + "sLoadFailedMessage", + "sLoadGame", + "sLoadingErrorsMsg", + "sLoadingMessage1", + "sLoadingMessage14", + "sLoadingMessage15", + "sLoadingMessage2", + "sLoadingMessage3", + "sLoadingMessage4", + "sLoadingMessage5", + "sLoadingMessage9", + "sLoadLastSaveMsg", + "sLocal", + "sLockFail", + "sLockImpossible", + "sLockLevel", + "sLockSuccess", + "sLookDownXbox", + "sLookUpXbox", + "sLow", + "sLucDesc", + "sMagDesc", + "sMage", + "sMagic", + "sMagicAncestralGhostID", + "sMagicBonelordID", + "sMagicBoundBattleAxeID", + "sMagicBoundBootsID", + "sMagicBoundCuirassID", + "sMagicBoundDaggerID", + "sMagicBoundHelmID", + "sMagicBoundLeftGauntletID", + "sMagicBoundLongbowID", + "sMagicBoundLongswordID", + "sMagicBoundMaceID", + "sMagicBoundRightGauntletID", + "sMagicBoundShieldID", + "sMagicBoundSpearID", + "sMagicCannotRecast", + "sMagicCenturionSphereID", + "sMagicClannfearID", + "sMagicContractDisease", + "sMagicCorprusWorsens", + "sMagicCreature01ID", + "sMagicCreature02ID", + "sMagicCreature03ID", + "sMagicCreature04ID", + "sMagicCreature05ID", + "sMagicDaedrothID", + "sMagicDremoraID", + "sMagicEffects", + "sMagicFabricantID", + "sMagicFlameAtronachID", + "sMagicFrostAtronachID", + "sMagicGoldenSaintID", + "sMagicGreaterBonewalkerID", + "sMagicHungerID", + "sMagicInsufficientCharge", + "sMagicInsufficientSP", + "sMagicInvalidEffect", + "sMagicInvalidTarget", + "sMagicItem", + "sMagicLeastBonewalkerID", + "sMagicLockSuccess", + "sMagicMenu", + "sMagicOpenSuccess", + "sMagicPCResisted", + "sMagicScampID", + "sMagicSelectTitle", + "sMagicSkeletalMinionID", + "sMagicSkillFail", + "sMagicStormAtronachID", + "sMagicTab", + "sMagicTargetResisted", + "sMagicTargetResistsWeapons", + "sMagicWingedTwilightID", + "sMagnitude", + "sMagnitudeDes", + "sMake", + "sMap", + "sMaster", + "sMastPlugMismatchMsg", + "sMaximumSaveGameMessage", + "sMaxSale", + "sMedium", + "sMenu_Help_Delay", + "sMenu_Mode", + "sMenuModeXbox", + "sMenuNextXbox", + "sMenuPrevXbox", + "sMenus", + "sMessage1", + "sMessage2", + "sMessage3", + "sMessage4", + "sMessage5", + "sMessageQuestionAnswer1", + "sMessageQuestionAnswer2", + "sMessageQuestionAnswer3", + "sMiscTab", + "sMissingMastersMsg", + "sMonk", + "sMonthEveningstar", + "sMonthFirstseed", + "sMonthFrostfall", + "sMonthHeartfire", + "sMonthLastseed", + "sMonthMidyear", + "sMonthMorningstar", + "sMonthRainshand", + "sMonthSecondseed", + "sMonthSunsdawn", + "sMonthSunsdusk", + "sMonthSunsheight", + "sMore", + "sMortar", + "sMouse", + "sMouseFlip", + "sMouseWheelDownShort", + "sMouseWheelUpShort", + "sMove", + "sMoveDownXbox", + "sMoveUpXbox", + "sMusic", + "sName", + "sNameTitle", + "sNear", + "sNeedOneSkill", + "sNeedTwoSkills", + "sNewGame", + "sNext", + "sNextRank", + "sNextSpell", + "sNextSpellXbox", + "sNextWeapon", + "sNextWeaponXbox", + "sNightblade", + "sNo", + "sNoName", + "sNone", + "sNotifyMessage1", + "sNotifyMessage10", + "sNotifyMessage11", + "sNotifyMessage12", + "sNotifyMessage13", + "sNotifyMessage14", + "sNotifyMessage15", + "sNotifyMessage16", + "sNotifyMessage16_a", + "sNotifyMessage17", + "sNotifyMessage18", + "sNotifyMessage19", + "sNotifyMessage2", + "sNotifyMessage20", + "sNotifyMessage21", + "sNotifyMessage22", + "sNotifyMessage23", + "sNotifyMessage24", + "sNotifyMessage25", + "sNotifyMessage26", + "sNotifyMessage27", + "sNotifyMessage28", + "sNotifyMessage29", + "sNotifyMessage3", + "sNotifyMessage30", + "sNotifyMessage31", + "sNotifyMessage32", + "sNotifyMessage33", + "sNotifyMessage34", + "sNotifyMessage35", + "sNotifyMessage36", + "sNotifyMessage37", + "sNotifyMessage38", + "sNotifyMessage39", + "sNotifyMessage4", + "sNotifyMessage40", + "sNotifyMessage41", + "sNotifyMessage42", + "sNotifyMessage43", + "sNotifyMessage44", + "sNotifyMessage45", + "sNotifyMessage46", + "sNotifyMessage47", + "sNotifyMessage48", + "sNotifyMessage49", + "sNotifyMessage4XBOX", + "sNotifyMessage5", + "sNotifyMessage50", + "sNotifyMessage51", + "sNotifyMessage52", + "sNotifyMessage53", + "sNotifyMessage54", + "sNotifyMessage55", + "sNotifyMessage56", + "sNotifyMessage57", + "sNotifyMessage58", + "sNotifyMessage59", + "sNotifyMessage6", + "sNotifyMessage60", + "sNotifyMessage61", + "sNotifyMessage62", + "sNotifyMessage63", + "sNotifyMessage64", + "sNotifyMessage65", + "sNotifyMessage66", + "sNotifyMessage67", + "sNotifyMessage6a", + "sNotifyMessage7", + "sNotifyMessage8", + "sNotifyMessage9", + "sOff", + "sOffer", + "sOfferMenuTitle", + "sOK", + "sOn", + "sOnce", + "sOneHanded", + "sOnetypeEffectMessage", + "sonword", + "sOptions", + "sOptionsMenuXbox", + "spercent", + "sPerDesc", + "sPersuasion", + "sPersuasionMenuTitle", + "sPickUp", + "sPilgrim", + "spoint", + "spoints", + "sPotionSuccess", + "sPowerAlreadyUsed", + "sPowers", + "sPreferences", + "sPrefs", + "sPrev", + "sPrevSpell", + "sPrevSpellXbox", + "sPrevWeapon", + "sPrevWeaponXbox", + "sProfitValue", + "sQuality", + "sQuanityMenuMessage01", + "sQuanityMenuMessage02", + "sQuestionDeleteSpell", + "sQuestionMark", + "sQuick0Xbox", + "sQuick10Cmd", + "sQuick1Cmd", + "sQuick2Cmd", + "sQuick3Cmd", + "sQuick4Cmd", + "sQuick4Xbox", + "sQuick5Cmd", + "sQuick5Xbox", + "sQuick6Cmd", + "sQuick6Xbox", + "sQuick7Cmd", + "sQuick7Xbox", + "sQuick8Cmd", + "sQuick8Xbox", + "sQuick9Cmd", + "sQuick9Xbox", + "sQuick_Save", + "sQuickLoadCmd", + "sQuickLoadXbox", + "sQuickMenu", + "sQuickMenu1", + "sQuickMenu2", + "sQuickMenu3", + "sQuickMenu4", + "sQuickMenu5", + "sQuickMenu6", + "sQuickMenuInstruc", + "sQuickMenuTitle", + "sQuickSaveCmd", + "sQuickSaveXbox", + "sRace", + "sRaceMenu1", + "sRaceMenu2", + "sRaceMenu3", + "sRaceMenu4", + "sRaceMenu5", + "sRaceMenu6", + "sRaceMenu7", + "sRacialTraits", + "sRange", + "sRangeDes", + "sRangeSelf", + "sRangeTarget", + "sRangeTouch", + "sReady_Magic", + "sReady_Weapon", + "sReadyItemXbox", + "sReadyMagicXbox", + "sRechargeEnchantment", + "sRender_Distance", + "sRepair", + "sRepairFailed", + "sRepairServiceTitle", + "sRepairSuccess", + "sReputation", + "sResChangeWarning", + "sRest", + "sRestIllegal", + "sRestKey", + "sRestMenu1", + "sRestMenu2", + "sRestMenu3", + "sRestMenu4", + "sRestMenuXbox", + "sRestore", + "sRetort", + "sReturnToGame", + "sRight", + "sRogue", + "sRun", + "sRunXbox", + "sSave", + "sSaveGame", + "sSaveGameDenied", + "sSaveGameFailed", + "sSaveGameNoMemory", + "sSaveGameTooBig", + "sSaveMenu1", + "sSaveMenuHelp01", + "sSaveMenuHelp02", + "sSaveMenuHelp03", + "sSaveMenuHelp04", + "sSaveMenuHelp05", + "sSaveMenuHelp06", + "sSchool", + "sSchoolAlteration", + "sSchoolConjuration", + "sSchoolDestruction", + "sSchoolIllusion", + "sSchoolMysticism", + "sSchoolRestoration", + "sScout", + "sScrolldown", + "sScrollup", + "ssecond", + "sseconds", + "sSeldom", + "sSelect", + "sSell", + "sSellerGold", + "sService", + "sServiceRefusal", + "sServiceRepairTitle", + "sServiceSpellsTitle", + "sServiceTrainingTitle", + "sServiceTrainingWords", + "sServiceTravelTitle", + "sSetValueMessage01", + "sSex", + "sShadows", + "sShadowText", + "sShift", + "sSkill", + "sSkillAcrobatics", + "sSkillAlchemy", + "sSkillAlteration", + "sSkillArmorer", + "sSkillAthletics", + "sSkillAxe", + "sSkillBlock", + "sSkillBluntweapon", + "sSkillClassMajor", + "sSkillClassMinor", + "sSkillClassMisc", + "sSkillConjuration", + "sSkillDestruction", + "sSkillEnchant", + "sSkillHandtohand", + "sSkillHeavyarmor", + "sSkillIllusion", + "sSkillLightarmor", + "sSkillLongblade", + "sSkillMarksman", + "sSkillMaxReached", + "sSkillMediumarmor", + "sSkillMercantile", + "sSkillMysticism", + "sSkillProgress", + "sSkillRestoration", + "sSkillSecurity", + "sSkillShortblade", + "sSkillsMenu1", + "sSkillsMenuReputationHelp", + "sSkillSneak", + "sSkillSpear", + "sSkillSpeechcraft", + "sSkillUnarmored", + "sSlash", + "sSleepInterrupt", + "sSlideLeftXbox", + "sSlideRightXbox", + "sSlow", + "sSorceror", + "sSoulGem", + "sSoulGemsWithSouls", + "sSoultrapSuccess", + "sSpace", + "sSpdDesc", + "sSpecialization", + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationMenu1", + "sSpecializationStealth", + "sSpellmaking", + "sSpellmakingHelp1", + "sSpellmakingHelp2", + "sSpellmakingHelp3", + "sSpellmakingHelp4", + "sSpellmakingHelp5", + "sSpellmakingHelp6", + "sSpellmakingMenu1", + "sSpellmakingMenuTitle", + "sSpells", + "sSpellServiceTitle", + "sSpellsword", + "sStartCell", + "sStartCellError", + "sStartError", + "sStats", + "sStrafe", + "sStrDesc", + "sStrip", + "sSubtitles", + "sSystemMenuXbox", + "sTake", + "sTakeAll", + "sTargetCriticalStrike", + "sTaunt", + "sTauntFail", + "sTauntSuccess", + "sTeleportDisabled", + "sThief", + "sThrust", + "sTo", + "sTogglePOVCmd", + "sTogglePOVXbox", + "sToggleRunXbox", + "sTopics", + "sTotalCost", + "sTotalSold", + "sTraining", + "sTrainingServiceTitle", + "sTraits", + "sTransparency_Menu", + "sTrapFail", + "sTrapImpossible", + "sTrapped", + "sTrapSuccess", + "sTravel", + "sTravelServiceTitle", + "sTurn", + "sTurnLeftXbox", + "sTurnRightXbox", + "sTwoHanded", + "sType", + "sTypeAbility", + "sTypeBlightDisease", + "sTypeCurse", + "sTypeDisease", + "sTypePower", + "sTypeSpell", + "sUnequip", + "sUnlocked", + "sUntilHealed", + "sUse", + "sUserDefinedClass", + "sUses", + "sUseXbox", + "sValue", + "sVideo", + "sVideoWarning", + "sVoice", + "sWait", + "sWarrior", + "sWaterReflectUpdate", + "sWaterTerrainReflect", + "sWeaponTab", + "sWeight", + "sWerewolfAlarmMessage", + "sWerewolfPopup", + "sWerewolfRefusal", + "sWerewolfRestMessage", + "sWilDesc", + "sWitchhunter", + "sWorld", + "sWornTab", + "sXStrafe", + "sXTimes", + "sXTimesINT", + "sYes", + "sYourGold", + 0 + }; + + for (int i=0; gmstFloats[i]; i++) + { + ESM::GameSetting gmst; + gmst.mId = gmstFloats[i]; + gmst.mValue.setType (ESM::VT_Float); + gmst.mValue.setFloat (gmstFloatsValues[i]); + getData().getGmsts().add (gmst); + } + + for (int i=0; gmstIntegers[i]; i++) + { + ESM::GameSetting gmst; + gmst.mId = gmstIntegers[i]; + gmst.mValue.setType (ESM::VT_Int); + gmst.mValue.setInteger (gmstIntegersValues[i]); + getData().getGmsts().add (gmst); + } + + for (int i=0; gmstStrings[i]; i++) + { + ESM::GameSetting gmst; + gmst.mId = gmstStrings[i]; + gmst.mValue.setType (ESM::VT_String); + gmst.mValue.setString (""); + getData().getGmsts().add (gmst); + } +} + void CSMDoc::Document::addOptionalGmsts() { static const char *sFloats[] = @@ -185,15 +2103,21 @@ void CSMDoc::Document::createBase() { static const char *sGlobals[] = { - "Day", "DaysPassed", "GameHour", "Month", "PCRace", "PCVampire", "PCWerewolf", "PCYear", 0 + "Day", + "DaysPassed", + "GameHour", + "Month", + "PCRace", + "PCVampire", + "PCWerewolf", + "PCYear", + 0 }; for (int i=0; sGlobals[i]; ++i) { ESM::Global record; - record.mId = sGlobals[i]; - record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Long); if (i==0 || i==1) @@ -202,7 +2126,7 @@ void CSMDoc::Document::createBase() getData().getGlobals().add (record); } - /// \todo add GMSTs + addGmsts(); for (int i=0; i<27; ++i) { @@ -247,13 +2171,14 @@ CSMDoc::Document::Document (const std::vector& files, b connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int))); - // dummy implementation -> remove when proper save is implemented. + // dummy implementation -> remove when proper save is implemented. mSaveCount = 0; connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); } CSMDoc::Document::~Document() -{} +{ +} QUndoStack& CSMDoc::Document::getUndoStack() { diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index 94d5fe85c..1c6d9db2a 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -52,6 +52,8 @@ namespace CSMDoc void createBase(); + void addGmsts(); + void addOptionalGmsts(); void addOptionalGlobals(); diff --git a/apps/opencs/model/settings/settingcontainer.hpp b/apps/opencs/model/settings/settingcontainer.hpp index eb264248d..5af298a57 100644 --- a/apps/opencs/model/settings/settingcontainer.hpp +++ b/apps/opencs/model/settings/settingcontainer.hpp @@ -15,21 +15,31 @@ namespace CSMSettings QStringList *mValues; public: + explicit SettingContainer (QObject *parent = 0); explicit SettingContainer (const QString &value, QObject *parent = 0); - virtual QString getName() const {return "";} - + /// add a value to the container + /// multiple values supported void insert (const QString &value); + + /// update an existing value + /// index specifies multiple values void update (const QString &value, int index = 0); + /// return value at specified index QString getValue (int index = -1) const; + + /// retrieve list of all values inline QStringList *getValues() const { return mValues; } + + /// return size of list int count() const; - //test for empty container - //useful for default-constructed containers returned by QMap when invalid key is passed + /// test for empty container + /// useful for default-constructed containers returned by QMap when invalid key is passed inline bool isEmpty() const { return (!mValue && !mValues); } + inline bool isMultiValue() const { return (mValues); } }; } diff --git a/apps/opencs/model/settings/settingsitem.cpp b/apps/opencs/model/settings/settingsitem.cpp index fef9d3e2f..5d897448a 100644 --- a/apps/opencs/model/settings/settingsitem.cpp +++ b/apps/opencs/model/settings/settingsitem.cpp @@ -1,5 +1,7 @@ #include "settingsitem.hpp" +#include + bool CSMSettings::SettingsItem::updateItem (const QStringList *values) { QStringList::ConstIterator it = values->begin(); @@ -66,21 +68,21 @@ bool CSMSettings::SettingsItem::updateItem(int valueListIndex) bool CSMSettings::SettingsItem::validate (const QString &value) { - bool isValid = true; + //if there is no value list or value pair, there is no validation to do + bool isValid = !(!mValueList->isEmpty() || mValuePair); - //validation required only if a value list or min/max value pair has been provided - if (mValueList->size()>0) + if (!isValid && !mValueList->isEmpty()) { - for (QStringList::ConstIterator it = mValueList->begin(); it !=mValueList->end(); ++it) + for (QStringList::Iterator it = mValueList->begin(); it != mValueList->end(); ++it) + // foreach (QString listItem, *mValueList) { - isValid = ( value == *it); + isValid = (value == *it); if (isValid) break; } } - - else if (mValuePair) + else if (!isValid && mValuePair) { int numVal = value.toInt(); diff --git a/apps/opencs/model/settings/settingsitem.hpp b/apps/opencs/model/settings/settingsitem.hpp index 8be05a4c7..c2587e892 100644 --- a/apps/opencs/model/settings/settingsitem.hpp +++ b/apps/opencs/model/settings/settingsitem.hpp @@ -7,12 +7,13 @@ namespace CSMSettings { + /// Represents a setting including metadata + /// (valid values, ranges, defaults, and multivalue status class SettingsItem : public SettingContainer { QStringPair *mValuePair; QStringList *mValueList; bool mIsMultiValue; - QString mName; QString mDefaultValue; public: @@ -20,26 +21,41 @@ namespace CSMSettings const QString& defaultValue, QObject *parent = 0) : SettingContainer(defaultValue, parent), mIsMultiValue (isMultiValue), mValueList (0), - mName (name), mValuePair (0), mDefaultValue (defaultValue) - {} + mValuePair (0), mDefaultValue (defaultValue) + { + QObject::setObjectName(name); + } + /// updateItem overloads for updating setting value + /// provided a list of values (multi-valued), + /// a specific value + /// or an index value corresponding to the mValueList bool updateItem (const QStringList *values); bool updateItem (const QString &value); bool updateItem (int valueListIndex); + /// retroeve list of valid values for setting inline QStringList *getValueList() { return mValueList; } + + /// write list of valid values for setting inline void setValueList (QStringList *valueList) { mValueList = valueList; } + /// valuePair used for spin boxes (max / min) inline QStringPair *getValuePair() { return mValuePair; } + + /// set value range (spinbox / integer use) inline void setValuePair (QStringPair valuePair) { mValuePair = new QStringPair(valuePair); } - inline QString getName () const { return mName; } inline bool isMultivalue () { return mIsMultiValue; } void setDefaultValue (const QString &value); QString getDefaultValue () const; private: + + /// Verifies that the supplied value is one of the following: + /// 1. Within the limits of the value pair (min / max) + /// 2. One of the values indicated in the value list bool validate (const QString &value); }; } diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index aabda86b3..b73fbfdf4 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -8,11 +8,13 @@ #include #include +#include +#include + #include - #include "settingcontainer.hpp" - #include + /** * Workaround for problems with whitespaces in paths in older versions of Boost library */ @@ -29,109 +31,236 @@ namespace boost } /* namespace boost */ #endif /* (BOOST_VERSION <= 104600) */ +CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0; CSMSettings::UserSettings::UserSettings() { + assert(!mUserSettingsInstance); mUserSettingsInstance = this; + + mReadWriteMessage = QObject::tr("
Could not open or create file for writing

\ + Please make sure you have the right permissions and try again.
"); + + mReadOnlyMessage = QObject::tr("
Could not open file for reading

\ + Please make sure you have the right permissions and try again.
"); } CSMSettings::UserSettings::~UserSettings() { + mUserSettingsInstance = 0; } -QFile *CSMSettings::UserSettings::openFile (const QString &filename) +QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly) const { - QFile *file = new QFile(filename); + QIODevice::OpenMode openFlags = QIODevice::Text; - bool success = (file->open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) ; + if (isReadOnly) + openFlags = QIODevice::ReadOnly | openFlags; + else + openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags; - if (!success) + QFile *file = new QFile(filePath); + QTextStream *stream = 0; + + if (file->open(openFlags)) { - // File cannot be opened or created - QMessageBox msgBox; - msgBox.setWindowTitle(QObject::tr("Error writing OpenMW configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open or create %0 for writing

\ - Please make sure you have the right permissions \ - and try again.
").arg(file->fileName())); - msgBox.exec(); - delete file; - file = 0; + stream = new QTextStream(file); + stream->setCodec(QTextCodec::codecForName("UTF-8")); } - return file; + return stream; + } -bool CSMSettings::UserSettings::writeFile(QFile *file, QMap &settings) +bool CSMSettings::UserSettings::writeSettings(QMap &settings) { - if (!file) + QTextStream *stream = openFileStream(mUserFilePath); + + bool success = (stream); + + if (success) + { + QList keyList = settings.keys(); + + foreach (QString key, keyList) + { + SettingList *sectionSettings = settings[key]; + + *stream << "[" << key << "]" << '\n'; + + foreach (SettingContainer *item, *sectionSettings) + *stream << item->objectName() << " = " << item->getValue() << '\n'; + } + + stream->device()->close(); + delete stream; + stream = 0; + } + else + { + displayFileErrorMessage(mReadWriteMessage, false); + } + + return (success); +} + + +const CSMSettings::SectionMap &CSMSettings::UserSettings::getSettings() const +{ + return mSectionSettings; +} + +bool CSMSettings::UserSettings::loadFromFile(const QString &filePath) +{ + if (filePath.isEmpty()) return false; - QTextStream stream(file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); + mSectionSettings.clear(); - QList keyList = settings.keys(); + QTextStream *stream = openFileStream (filePath, true); - foreach (QString key, keyList) + bool success = (stream); + + if (success) { - SettingList *sectionSettings = settings[key]; + //looks for a square bracket, "'\\[" + //that has one or more "not nothing" in it, "([^]]+)" + //and is closed with a square bracket, "\\]" - stream << "[" << key << "]" << '\n'; + QRegExp sectionRe("^\\[([^]]+)\\]"); - foreach (SettingContainer *item, *sectionSettings) - stream << item->getName() << " = " << item->getValue() << '\n'; + //Find any character(s) that is/are not equal sign(s), "[^=]+" + //followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*" + //and one or more periods, "(.+)" + + QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); + + CSMSettings::SettingMap *settings = 0; + QString section = "none"; + + while (!stream->atEnd()) + { + QString line = stream->readLine().simplified(); + + if (line.isEmpty() || line.startsWith("#")) + continue; + + //if a section is found, push it onto a new QStringList + //and push the QStringList onto + if (sectionRe.exactMatch(line)) + { + //add the previous section's settings to the member map + if (settings) + mSectionSettings.insert(section, settings); + + //save new section and create a new list + section = sectionRe.cap(1); + settings = new SettingMap; + continue; + } + + if (keyRe.indexIn(line) != -1) + { + SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified()); + sc->setObjectName(keyRe.cap(1).simplified()); + (*settings)[keyRe.cap(1).simplified()] = sc; + } + + } + + mSectionSettings.insert(section, settings); + + stream->device()->close(); + delete stream; + stream = 0; } - file->close(); - - return true; + return success; } -void CSMSettings::UserSettings::getSettings(QTextStream &stream, SectionMap §ions) +void CSMSettings::UserSettings::loadSettings (const QString &fileName) { - //looks for a square bracket, "'\\[" - //that has one or more "not nothing" in it, "([^]]+)" - //and is closed with a square bracket, "\\]" + //global + QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName; + bool globalOk = loadFromFile(globalFilePath); - QRegExp sectionRe("^\\[([^]]+)\\]"); - //Find any character(s) that is/are not equal sign(s), "[^=]+" - //followed by an optional whitespace, an equal sign, and another optional whirespace, "\\s*=\\s*" - //and one or more periods, "(.+)" + //local + QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName; + bool localOk = loadFromFile(localFilePath); - QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$"); + //user + mUserFilePath = QString::fromStdString(mCfgMgr.getUserPath().string()) + fileName; + loadFromFile(mUserFilePath); - CSMSettings::SettingMap *settings = 0; - QString section = "none"; - - while (!stream.atEnd()) + if (!(localOk || globalOk)) { - QString line = stream.readLine().simplified(); + QString message = QObject::tr("
Could not open user settings files for reading

\ + Global and local settings files could not be read.\ + You may have incorrect file permissions or the OpenCS installation may be corrupted.
"); - if (line.isEmpty() || line.startsWith("#")) - continue; - - //if a section is found, push it onto a new QStringList - //and push the QStringList onto - if (sectionRe.exactMatch(line)) - { - //add the previous section's settings to the member map - if (settings) - sections.insert(section, settings); - - //save new section and create a new list - section = sectionRe.cap(1); - settings = new SettingMap; - continue; - } - - if (keyRe.indexIn(line) != -1) - { - SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified()); - (*settings)[keyRe.cap(1).simplified()] = sc; - } + message += QObject::tr("
Global filepath: ") + globalFilePath; + message += QObject::tr("
Local filepath: ") + localFilePath; + displayFileErrorMessage ( message, true); } - sections.insert(section, settings); +} + +void CSMSettings::UserSettings::updateSettings (const QString §ionName, const QString &settingName) +{ + if (mSectionSettings.find(sectionName) == mSectionSettings.end()) + return; + + SettingMap *settings = mSectionSettings.value(sectionName); + + if (settingName.isEmpty()) + { + foreach (const SettingContainer *setting, *settings) + emit signalUpdateEditorSetting (setting->objectName(), setting->getValue()); + } + else + { + if (settings->find(settingName) != settings->end()) + { + const SettingContainer *setting = settings->value(settingName); + emit signalUpdateEditorSetting (setting->objectName(), setting->getValue()); + } + } +} + +QString CSMSettings::UserSettings::getSetting (const QString §ion, const QString &setting) const +{ + QString retVal = ""; + + if (mSectionSettings.find(section) != mSectionSettings.end()) + { + CSMSettings::SettingMap *settings = mSectionSettings.value(section); + + if (settings->find(setting) != settings->end()) + retVal = settings->value(setting)->getValue(); + } + + return retVal; +} + +CSMSettings::UserSettings& CSMSettings::UserSettings::instance() +{ + assert(mUserSettingsInstance); + return *mUserSettingsInstance; +} + +void CSMSettings::UserSettings::displayFileErrorMessage(const QString &message, bool isReadOnly) +{ + // File cannot be opened or created + QMessageBox msgBox; + msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + + if (!isReadOnly) + msgBox.setText (mReadWriteMessage + message); + else + msgBox.setText (message); + + msgBox.exec(); } diff --git a/apps/opencs/model/settings/usersettings.hpp b/apps/opencs/model/settings/usersettings.hpp index 343702eda..49b226df9 100644 --- a/apps/opencs/model/settings/usersettings.hpp +++ b/apps/opencs/model/settings/usersettings.hpp @@ -10,6 +10,10 @@ #include "support.hpp" +#ifndef Q_MOC_RUN +#include +#endif + namespace Files { typedef std::vector PathContainer; struct ConfigurationManager;} @@ -22,29 +26,56 @@ namespace CSMSettings { Q_OBJECT + SectionMap mSectionSettings; + static UserSettings *mUserSettingsInstance; + QString mUserFilePath; + Files::ConfigurationManager mCfgMgr; + QString mReadOnlyMessage; + QString mReadWriteMessage; + public: - static UserSettings &instance() - { - static UserSettings instance; + /// Singleton implementation + static UserSettings& instance(); - return instance; - } - - QFile *openFile (const QString &); - bool writeFile(QFile *file, QMap §ions); - void getSettings (QTextStream &stream, SectionMap &settings); - - private: - - UserSettings *mUserSettingsInstance; UserSettings(); ~UserSettings(); UserSettings (UserSettings const &); //not implemented void operator= (UserSettings const &); //not implemented + /// Writes settings to the last loaded settings file + bool writeSettings(QMap §ions); + + /// Called from editor to trigger signal to update the specified setting. + /// If no setting name is specified, all settings found in the specified section are updated. + void updateSettings (const QString §ionName, const QString &settingName = ""); + + /// Retrieves the settings file at all three levels (global, local and user). + + /// \todo Multi-valued settings are not fully implemented. Setting values + /// \todo loaded in later files will always overwrite previously loaded values. + void loadSettings (const QString &fileName); + + /// Returns the entire map of settings across all sections + const SectionMap &getSettings () const; + + /// Retrieves the value as a QString of the specified setting in the specified section + QString getSetting(const QString §ion, const QString &setting) const; + + private: + + + /// Opens a QTextStream from the provided path as read-only or read-write. + QTextStream *openFileStream (const QString &filePath, bool isReadOnly = false) const; + + /// Parses a setting file specified in filePath from the provided text stream. + bool loadFromFile (const QString &filePath = ""); + + void displayFileErrorMessage(const QString &message, bool isReadOnly); + signals: + void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 8cc435f3a..e71e633a4 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -41,7 +41,8 @@ namespace CSMWorld Display_ArmorType, Display_ClothingType, Display_CreatureType, - Display_WeaponType + Display_WeaponType, + Display_RecordState }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index ba60aaf90..c0994f381 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -53,7 +53,7 @@ namespace CSMWorld template struct RecordStateColumn : public Column { - RecordStateColumn() : Column ("*", ColumnBase::Display_Integer) {} + RecordStateColumn() : Column ("*", ColumnBase::Display_RecordState) {} virtual QVariant get (const Record& record) const { @@ -1148,4 +1148,4 @@ namespace CSMWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 37210d989..e4936afa6 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -41,7 +41,7 @@ CSMWorld::RefIdCollection::RefIdCollection() mColumns.push_back (RefIdColumn ("ID", ColumnBase::Display_String, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); baseColumns.mId = &mColumns.back(); - mColumns.push_back (RefIdColumn ("*", ColumnBase::Display_Integer, + mColumns.push_back (RefIdColumn ("*", ColumnBase::Display_RecordState, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); baseColumns.mModified = &mColumns.back(); mColumns.push_back (RefIdColumn ("Type", ColumnBase::Display_Integer, @@ -539,4 +539,4 @@ void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, Univers int CSMWorld::RefIdCollection::getAppendIndex (UniversalId::Type type) const { return mData.getAppendIndex (type); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index affada012..731adabb3 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -1,5 +1,6 @@ #include "subview.hpp" + CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id) { /// \todo add a button to the title bar that clones this sub view @@ -15,3 +16,7 @@ CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const { return mUniversalId; } + +void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QString &settingValue) +{ +} diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 985c5eb3c..280a2a487 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -35,6 +35,7 @@ namespace CSVDoc CSMWorld::UniversalId getUniversalId() const; virtual void setEditLock (bool locked) = 0; + virtual void updateEditorSetting (const QString &, const QString &); signals: @@ -42,4 +43,4 @@ namespace CSVDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 08b4b78fe..bcc020350 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -182,7 +182,13 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - resize (300, 300); /// \todo get default size from settings and set reasonable minimal size + QString width = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Width")); + QString height = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Height")); + + if(width==QString() || height==QString()) + resize(800, 600); + else + resize (width.toInt(), height.toInt()); mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); @@ -261,11 +267,14 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) SubView *view = mSubViewFactory.makeSubView (id, *mDocument); + view->setObjectName ("subview"); mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, SLOT (addSubView (const CSMWorld::UniversalId&))); + CSMSettings::UserSettings::instance().updateSettings("Editor", "Record Status Display"); + view->show(); } @@ -374,20 +383,34 @@ void CSVDoc::View::showUserSettings() { CSVSettings::UserSettingsDialog *settingsDialog = new CSVSettings::UserSettingsDialog(this); - connect (&(CSMSettings::UserSettings::instance()), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)), - this, SLOT (slotUpdateEditorSetting (const QString &, const QString &)) ); - settingsDialog->show(); } -void CSVDoc::View::slotUpdateEditorSetting(const QString &settingName, const QString &settingValue) +void CSVDoc::View::resizeViewWidth (int width) { - static QString lastValue = ""; - - if (lastValue != settingValue) - { - //evaluate settingName against tokens to determine which function to call to update Editor application. - - lastValue = settingValue; - } + if (width >= 0) + resize (width, geometry().height()); +} + +void CSVDoc::View::resizeViewHeight (int height) +{ + if (height >= 0) + resize (geometry().width(), height); +} + +void CSVDoc::View::updateEditorSetting (const QString &settingName, const QString &settingValue) +{ + if (settingName == "Record Status Display") + { + foreach (QObject *view, mSubViewWindow.children()) + { + if (view->objectName() == "subview") + dynamic_cast(view)->updateEditorSetting (settingName, settingValue); + } + } + else if (settingName == "Width") + resizeViewWidth (settingValue.toInt()); + + else if (settingName == "Height") + resizeViewHeight (settingValue.toInt()); } diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 6b7fd23b3..b3c4ae22a 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -68,6 +68,14 @@ namespace CSVDoc void exitApplication(); + void loadUserSettings(); + + /// User preference function + void resizeViewWidth (int width); + + /// User preference function + void resizeViewHeight (int height); + public: View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); @@ -88,6 +96,9 @@ namespace CSVDoc Operations *getOperations() const; + /// Function called by view manager when user preferences are updated + void updateEditorSetting (const QString &, const QString &); + signals: void newDocumentRequest(); @@ -102,8 +113,6 @@ namespace CSVDoc void abortOperation (int type); - void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue); - private slots: void newView(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index d044098fe..bf9da68a0 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -12,13 +12,14 @@ #include "../world/util.hpp" #include "../world/enumdelegate.hpp" #include "../world/vartypedelegate.hpp" +#include "../world/recordstatusdelegate.hpp" +#include "../settings/usersettingsdialog.hpp" #include "view.hpp" #include #include #include -#include void CSVDoc::ViewManager::updateIndices() { @@ -117,6 +118,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_WeaponType, new CSVWorld::EnumDelegateFactory (sWeaponTypes)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_RecordState, + new CSVWorld::RecordStatusDelegateFactory() ); + + connect (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)), + this, SLOT (slotUpdateEditorSetting (const QString &, const QString &))); } CSVDoc::ViewManager::~ViewManager() @@ -343,3 +350,13 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) if (notifySaveOnClose (view)) QApplication::instance()->exit(); } + +void CSVDoc::ViewManager::slotUpdateEditorSetting (const QString &settingName, const QString &settingValue) +{ + if (settingName == "Record Status Display" || + settingName == "Width" || settingName == "Height") + { + foreach (CSVDoc::View *view, mViews) + view->updateEditorSetting (settingName, settingValue); + } +} diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 90f23eaa1..1f4dcd51b 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -72,6 +72,9 @@ namespace CSVDoc void progress (int current, int max, int type, int threads, CSMDoc::Document *document); void onExitWarningHandler(int state, CSMDoc::Document* document); + + /// connected to update signal in UserSettings + void slotUpdateEditorSetting (const QString &, const QString &); }; } diff --git a/apps/opencs/view/settings/abstractblock.cpp b/apps/opencs/view/settings/abstractblock.cpp index 72d360348..65825ce8b 100644 --- a/apps/opencs/view/settings/abstractblock.cpp +++ b/apps/opencs/view/settings/abstractblock.cpp @@ -38,27 +38,27 @@ CSVSettings::AbstractWidget *CSVSettings::AbstractBlock::buildWidget (const QStr { case Widget_RadioButton: - widg = createSettingWidget (def, layout); + widg = new SettingWidget (def, layout, mBox); break; case Widget_SpinBox: - widg = createSettingWidget (def, layout); + widg = new SettingWidget (def, layout, mBox); break; case Widget_CheckBox: - widg = createSettingWidget (def, layout); + widg = new SettingWidget (def, layout, mBox); break; case Widget_LineEdit: - widg = createSettingWidget (def, layout); + widg = new SettingWidget (def, layout, mBox); break; case Widget_ListBox: - widg = createSettingWidget (def, layout); + widg = new SettingWidget (def, layout, mBox); break; case Widget_ComboBox: - widg = createSettingWidget (def, layout); + widg = new SettingWidget (def, layout, mBox); break; default: diff --git a/apps/opencs/view/settings/abstractblock.hpp b/apps/opencs/view/settings/abstractblock.hpp index 42e00b6d7..36108d752 100644 --- a/apps/opencs/view/settings/abstractblock.hpp +++ b/apps/opencs/view/settings/abstractblock.hpp @@ -11,6 +11,7 @@ namespace CSVSettings { + /// Abstract base class for all blocks class AbstractBlock : public QObject { Q_OBJECT @@ -31,40 +32,50 @@ namespace CSVSettings bool isVisible() const; virtual CSMSettings::SettingList *getSettings() = 0; + + /// update settings found in the passed map and are encapsulated by the block virtual bool updateSettings (const CSMSettings::SettingMap &settings) = 0; + + /// update callback function called from update slot + /// used for updating application-level settings in the editor virtual bool updateBySignal (const QString &name, const QString &value, bool &doEmit) { return false; } protected: + /// Creates the layout which for the blocks QGroupBox QLayout *createLayout (Orientation direction, bool isZeroMargin, QWidget* parent = 0); + + /// Creates widgets that exist as direct children of the block AbstractWidget *buildWidget (const QString &widgetName, WidgetDef &wDef, QLayout *layout = 0, bool isConnected = true) const; - template - AbstractWidget *createSettingWidget (WidgetDef &wDef, QLayout *layout) const - { - return new SettingWidget (wDef, layout, mBox); - } - QWidget *getParent() const; public slots: + /// enables / disables block-level widgets based on signals from other widgets + /// used in ToggleBlock void slotSetEnabled (bool value); + + /// receives updates to applicaion-level settings in the Editor void slotUpdateSetting (const QString &settingName, const QString &settingValue); private slots: + /// receives updates to a setting in the block pushed from the application level void slotUpdate (const QString &value); signals: - //signal to functions outside the settings tab widget + /// signal to UserSettings instance void signalUpdateSetting (const QString &propertyName, const QString &propertyValue); + + /// signal to widget for updating widget value void signalUpdateWidget (const QString & value); - //propertyName and propertyValue are for properties for which the updated setting acts as a proxy + /// ProxyBlock use only. + /// Name and value correspond to settings for which the block is a proxy. void signalUpdateProxySetting (const QString &propertyName, const QString &propertyValue); }; } diff --git a/apps/opencs/view/settings/abstractpage.cpp b/apps/opencs/view/settings/abstractpage.cpp index 512b5abbd..e6c605275 100644 --- a/apps/opencs/view/settings/abstractpage.cpp +++ b/apps/opencs/view/settings/abstractpage.cpp @@ -13,12 +13,17 @@ CSVSettings::AbstractPage::AbstractPage(QWidget *parent): QWidget(parent) { + QGridLayout *pageLayout = new QGridLayout(this); + setLayout (pageLayout); } CSVSettings::AbstractPage::AbstractPage(const QString &pageName, QWidget *parent): QWidget(parent) { QWidget::setObjectName (pageName); + + QGridLayout *pageLayout = new QGridLayout(this); + setLayout (pageLayout); } CSVSettings::AbstractPage::~AbstractPage() diff --git a/apps/opencs/view/settings/abstractpage.hpp b/apps/opencs/view/settings/abstractpage.hpp index 15ac82a62..77ef4524f 100644 --- a/apps/opencs/view/settings/abstractpage.hpp +++ b/apps/opencs/view/settings/abstractpage.hpp @@ -14,6 +14,11 @@ namespace CSVSettings { typedef QList AbstractBlockList; + /// Abstract base class for all setting pages in the dialog + + /// \todo Scripted implementation of settings should eliminate the need + /// \todo derive page classes. + /// \todo AbstractPage should be replaced with a general page construction class. class AbstractPage: public QWidget { @@ -28,18 +33,24 @@ namespace CSVSettings { ~AbstractPage(); - virtual void setupUi()=0; + virtual void setupUi() = 0; + /// triggers widgiet initialization at the page level. All widgets updated to + /// current setting values virtual void initializeWidgets (const CSMSettings::SettingMap &settings) = 0; + /// retrieve the list of settings local to the page. CSMSettings::SettingList *getSettings(); void setObjectName(); protected: + /// Create a block for the page. + /// Block is constructed using passed definition struct + /// Page level-layout is created and assigned template - AbstractBlock *buildBlock (T &def) + AbstractBlock *buildBlock (T *def) { S *block = new S (this); int ret = block->build (def); @@ -47,12 +58,12 @@ namespace CSVSettings { if (ret < 0) return 0; - QWidget::layout()->addWidget (block->getGroupBox()); + QGroupBox *box = block->getGroupBox(); + QWidget::layout()->addWidget (box); return block; } - }; } diff --git a/apps/opencs/view/settings/abstractwidget.hpp b/apps/opencs/view/settings/abstractwidget.hpp index ef00993fc..325de2bd2 100644 --- a/apps/opencs/view/settings/abstractwidget.hpp +++ b/apps/opencs/view/settings/abstractwidget.hpp @@ -8,6 +8,7 @@ class QLayout; namespace CSVSettings { + /// Abstract base class for widgets which are used in user preferences dialog class AbstractWidget : public QObject { Q_OBJECT @@ -16,45 +17,49 @@ namespace CSVSettings public: + /// Passed layout is assigned the constructed widget. + /// if no layout is passed, one is created. explicit AbstractWidget (QLayout *layout = 0, QWidget* parent = 0) : QObject (parent), mLayout (layout) {} - //retrieve layout for insertion into itemblock + /// retrieve layout for insertion into itemblock QLayout *getLayout(); - //create the derived widget instance + /// create the derived widget instance void build (QWidget* widget, WidgetDef &def, bool noLabel = false); - //reference to the derived widget instance + /// reference to the derived widget instance virtual QWidget *widget() = 0; protected: - //called by inbound signal for type-specific widget udpates + /// Callback called by receiving slot for widget udpates virtual void updateWidget (const QString &value) = 0; - //converts user-defined enum to Qt equivalents + /// Converts user-defined enum to Qt equivalents QFlags getAlignment (Alignment flag); private: - //widget initialization utilities + /// Creates layout and assigns label and widget as appropriate void createLayout (Orientation direction, bool isZeroMargin); + + /// Creates label and widget according to passed definition void buildLabelAndWidget (QWidget *widget, WidgetDef &def, bool noLabel); signals: - //outbound update + /// outbound update signal void signalUpdateItem (const QString &value); public slots: - //inbound updates + /// receives inbound updates void slotUpdateWidget (const QString &value); - //Outbound updates from derived widget signal + /// Overloads for outbound updates from derived widget signal void slotUpdateItem (const QString &value); void slotUpdateItem (bool value); void slotUpdateItem (int value); diff --git a/apps/opencs/view/settings/blankpage.cpp b/apps/opencs/view/settings/blankpage.cpp index 57d5c7caa..837a31bee 100644 --- a/apps/opencs/view/settings/blankpage.cpp +++ b/apps/opencs/view/settings/blankpage.cpp @@ -20,16 +20,11 @@ CSVSettings::BlankPage::BlankPage(QWidget *parent): AbstractPage("Blank", parent) { - initPage(); + } CSVSettings::BlankPage::BlankPage(const QString &title, QWidget *parent): AbstractPage(title, parent) -{ - initPage(); -} - -void CSVSettings::BlankPage::initPage() { // Hacks to get the stylesheet look properly #ifdef Q_OS_MAC @@ -43,10 +38,7 @@ void CSVSettings::BlankPage::initPage() void CSVSettings::BlankPage::setupUi() { QGroupBox *pageBox = new QGroupBox(this); - QLayout* pageLayout = new QVBoxLayout(); - - setLayout(pageLayout); - pageLayout->addWidget(pageBox); + layout()->addWidget(pageBox); } void CSVSettings::BlankPage::initializeWidgets (const CSMSettings::SettingMap &settings) diff --git a/apps/opencs/view/settings/blankpage.hpp b/apps/opencs/view/settings/blankpage.hpp index 648d373f3..07049fb71 100644 --- a/apps/opencs/view/settings/blankpage.hpp +++ b/apps/opencs/view/settings/blankpage.hpp @@ -10,6 +10,8 @@ namespace CSVSettings { class UserSettings; class AbstractBlock; + /// Derived page with no widgets + /// Reference use only. class BlankPage : public AbstractPage { @@ -20,9 +22,6 @@ namespace CSVSettings { void setupUi(); void initializeWidgets (const CSMSettings::SettingMap &settings); - - private: - void initPage(); }; } diff --git a/apps/opencs/view/settings/customblock.cpp b/apps/opencs/view/settings/customblock.cpp index f44189569..bbceafabe 100644 --- a/apps/opencs/view/settings/customblock.cpp +++ b/apps/opencs/view/settings/customblock.cpp @@ -23,7 +23,7 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis for (; listIt != defList.end(); ++listIt) { if (!(*listIt)->isProxy) - retVal = buildGroupBlock (*(*listIt)); + retVal = buildGroupBlock (*listIt); else { mGroupList << proxyBlock; @@ -32,7 +32,7 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis } if (proxyIt != defaultIt) - retVal = buildProxyBlock (*(*proxyIt), proxyBlock); + retVal = buildProxyBlock (*proxyIt, proxyBlock); return retVal; } @@ -40,12 +40,12 @@ int CSVSettings::CustomBlock::build(GroupBlockDefList &defList, GroupBlockDefLis CSVSettings::GroupBox *CSVSettings::CustomBlock::buildGroupBox (Orientation orientation) { GroupBox *box = new GroupBox (false, mBox); - QLayout *layout = createLayout (orientation, true, box); + createLayout (orientation, true, box); return box; } -int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef &def) +int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef *def) { GroupBlock *block = new GroupBlock (getParent()); @@ -57,9 +57,9 @@ int CSVSettings::CustomBlock::buildGroupBlock(GroupBlockDef &def) return block->build(def); } -int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef& def, ProxyBlock *block) +int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef *def, ProxyBlock *block) { - if (def.properties.size() != 1) + if (def->settingItems.size() != 1) return -1; int retVal = block->build(def); @@ -67,7 +67,8 @@ int CSVSettings::CustomBlock::buildProxyBlock(GroupBlockDef& def, ProxyBlock *bl if (retVal != 0) return retVal; - foreach (QStringList *list, *(def.properties.at(0)->proxyList)) + // The first settingItem is the proxy setting, containing the list of settings bound to it. + foreach (QStringList *list, *(def->settingItems.at(0)->proxyList)) { QString proxiedBlockName = list->at(0); diff --git a/apps/opencs/view/settings/customblock.hpp b/apps/opencs/view/settings/customblock.hpp index b2f2a0261..54c50f395 100644 --- a/apps/opencs/view/settings/customblock.hpp +++ b/apps/opencs/view/settings/customblock.hpp @@ -8,6 +8,8 @@ namespace CSVSettings class ProxyBlock; + /// Base class for customized user preference setting blocks + /// Special block classes should be derived from CustomBlock class CustomBlock : public AbstractBlock { @@ -19,18 +21,27 @@ namespace CSVSettings explicit CustomBlock (QWidget *parent = 0); + /// Update settings local to the block bool updateSettings (const CSMSettings::SettingMap &settings); + + /// Retrieve settings local to the block CSMSettings::SettingList *getSettings(); + + /// construct the block using the passed definition int build (GroupBlockDefList &defList, GroupBlockDefList::Iterator *it = 0); protected: + /// construct the block groupbox GroupBox *buildGroupBox (Orientation orientation); private: - int buildGroupBlock(GroupBlockDef &def); - int buildProxyBlock(GroupBlockDef &def, ProxyBlock *block); + /// Construction function for creating a standard GroupBlock child + int buildGroupBlock(GroupBlockDef *def); + + /// Construction function for creating a standard ProxyBlock child + int buildProxyBlock(GroupBlockDef *def, ProxyBlock *block); }; } #endif // CUSTOMBLOCK_HPP diff --git a/apps/opencs/view/settings/editorpage.cpp b/apps/opencs/view/settings/editorpage.cpp index ad5a15f6f..153ac1551 100644 --- a/apps/opencs/view/settings/editorpage.cpp +++ b/apps/opencs/view/settings/editorpage.cpp @@ -1,156 +1,46 @@ #include "editorpage.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_OS_MAC -#include -#endif - -#include "../../model/settings/usersettings.hpp" #include "groupblock.hpp" -#include "toggleblock.hpp" +#include "../../model/settings/usersettings.hpp" -CSVSettings::EditorPage::EditorPage(QWidget *parent): - AbstractPage("Editor", parent) +CSVSettings::EditorPage::EditorPage(QWidget* parent) : + AbstractPage("Display Format", parent) { - // Hacks to get the stylesheet look properly -#ifdef Q_OS_MAC - QPlastiqueStyle *style = new QPlastiqueStyle; - //profilesComboBox->setStyle(style); -#endif - setupUi(); } +CSVSettings::GroupBlockDef *CSVSettings::EditorPage::setupRecordStatusDisplay() +{ + GroupBlockDef *statusBlock = new GroupBlockDef(QString("Record Status Display")); + + SettingsItemDef *statusItem = new SettingsItemDef (statusBlock->title, "Icon and Text"); + *(statusItem->valueList) << QString("Icon and Text") << QString("Icon Only") << QString("Text Only"); + + WidgetDef statusWidget (Widget_RadioButton); + statusWidget.valueList = statusItem->valueList; + + statusItem->widget = statusWidget; + + statusBlock->settingItems << statusItem; + + return statusBlock; +} + void CSVSettings::EditorPage::setupUi() { - GroupBlockDef undoStack (QString("Undo Stack Size")); - GroupBlockDef topLevelWindowCount (QString("Maximum Top-Level Window Count")); - GroupBlockDef reuseSubwindow (QString("Reuse Subwindows")); - GroupBlockDef customWindowSize (QString ("Custom Window Size")); - GroupBlockDef definedWindowSize (QString ("Pre-Defined Window Size")); - GroupBlockDef windowSizeToggle (QString ("Window Size")); - CustomBlockDef windowSize (QString ("Window Size")); - //////////////////////////// - //undo stack size property - /////////////////////////// - - SettingsItemDef *undoStackItem = new SettingsItemDef (undoStack.title, "32"); - undoStack.properties << undoStackItem; - undoStackItem->minMax.left = "0"; - undoStackItem->minMax.right = "64"; - - WidgetDef stackWidget (Widget_SpinBox); - stackWidget.minMax = &(undoStackItem->minMax); - stackWidget.widgetWidth = 50; - - undoStackItem->widget = stackWidget; - - ////////////////////////////////////// - //number of top level windows property - ///////////////////////////////////// - - SettingsItemDef *topLevelItem = new SettingsItemDef (topLevelWindowCount.title, "100"); - topLevelWindowCount.properties << topLevelItem; - topLevelItem->minMax.left = "1"; - topLevelItem->minMax.right = "256"; - - WidgetDef topLvlWinWidget (Widget_SpinBox); - topLvlWinWidget.minMax = &(topLevelItem->minMax); - topLvlWinWidget.widgetWidth = 50; - - topLevelItem->widget = topLvlWinWidget; - - /////////////////////////// - //reuse subwindows property - //////////////////////////// - - SettingsItemDef *reuseSubItem = new SettingsItemDef (reuseSubwindow.title, "Reuse Subwindows"); - *(reuseSubItem->valueList) << "None" << "Top-Level" << "Document-Level"; - - WidgetDef reuseSubWidget (Widget_RadioButton); - reuseSubWidget.valueList = (reuseSubItem->valueList); - reuseSubWidget.widgetAlignment = Align_Left; - - reuseSubwindow.properties << reuseSubItem; - reuseSubItem->widget = reuseSubWidget; - - /////////////////////////////// - //custom window size properties - /////////////////////////////// - - //custom width - SettingsItemDef *widthItem = new SettingsItemDef ("Window Width", "640"); - widthItem->widget = WidgetDef (Widget_LineEdit); - widthItem->widget.widgetWidth = 45; - - //custom height - SettingsItemDef *heightItem = new SettingsItemDef ("Window Height", "480"); - heightItem->widget = WidgetDef (Widget_LineEdit); - heightItem->widget.widgetWidth = 45; - heightItem->widget.caption = "x"; - - customWindowSize.properties << widthItem << heightItem; - customWindowSize.widgetOrientation = Orient_Horizontal; - customWindowSize.isVisible = false; - - - //pre-defined - SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480"); - WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox); - widthByHeightWidget.widgetWidth = 90; - *(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768"; - - QStringList *widthProxy = new QStringList; - QStringList *heightProxy = new QStringList; - - (*widthProxy) << "Window Width" << "640" << "800" << "1024"; - (*heightProxy) << "Window Height" << "480" << "600" << "768"; - - *(widthByHeightItem->proxyList) << widthProxy << heightProxy; - - widthByHeightItem->widget = widthByHeightWidget; - - definedWindowSize.properties << widthByHeightItem; - definedWindowSize.isProxy = true; - definedWindowSize.isVisible = false; - - // window size toggle - windowSizeToggle.captions << "Pre-Defined" << "Custom"; - windowSizeToggle.widgetOrientation = Orient_Vertical; - windowSizeToggle.isVisible = false; - - //define a widget for each group in the toggle - for (int i = 0; i < 2; i++) - windowSizeToggle.widgets << new WidgetDef (Widget_RadioButton); - - windowSizeToggle.widgets.at(0)->isDefault = false; - - windowSize.blockDefList << &windowSizeToggle << &definedWindowSize << &customWindowSize; - windowSize.defaultValue = "Custom"; - - QGridLayout *pageLayout = new QGridLayout(this); - - setLayout (pageLayout); - - mAbstractBlocks << buildBlock (topLevelWindowCount) - << buildBlock (reuseSubwindow) - << buildBlock (windowSize) - << buildBlock (undoStack); + mAbstractBlocks << buildBlock(setupRecordStatusDisplay()); foreach (AbstractBlock *block, mAbstractBlocks) { connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) ); } + + connect ( this, + SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)), + &(CSMSettings::UserSettings::instance()), + SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &))); + } void CSVSettings::EditorPage::initializeWidgets (const CSMSettings::SettingMap &settings) diff --git a/apps/opencs/view/settings/editorpage.hpp b/apps/opencs/view/settings/editorpage.hpp index 0c1e80e89..85215edab 100644 --- a/apps/opencs/view/settings/editorpage.hpp +++ b/apps/opencs/view/settings/editorpage.hpp @@ -1,28 +1,33 @@ -#ifndef EDITORPAGE_H -#define EDITORPAGE_H +#ifndef EDITORPAGE_HPP +#define EDITORPAGE_HPP +#include "support.hpp" #include "abstractpage.hpp" -class QGroupBox; - -namespace CSVSettings { - - class UserSettings; - class AbstractBlock; - +namespace CSVSettings +{ class EditorPage : public AbstractPage { Q_OBJECT public: + explicit EditorPage(QWidget *parent = 0); - EditorPage(QWidget *parent = 0); - - void setupUi(); void initializeWidgets (const CSMSettings::SettingMap &settings); + void setupUi(); + + private: + + /// User preference view of the record status delegate's icon / text setting + GroupBlockDef *setupRecordStatusDisplay(); signals: + + /// Signals up for changes to editor application-level settings void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); + + public slots: }; } -#endif //EDITORPAGE_H + +#endif // EDITORPAGE_HPP diff --git a/apps/opencs/view/settings/groupblock.cpp b/apps/opencs/view/settings/groupblock.cpp index b18f629ba..85720ad41 100644 --- a/apps/opencs/view/settings/groupblock.cpp +++ b/apps/opencs/view/settings/groupblock.cpp @@ -9,22 +9,22 @@ CSVSettings::GroupBlock::GroupBlock (bool isVisible, QWidget *parent) : AbstractBlock (isVisible, parent) {} -int CSVSettings::GroupBlock::build (GroupBlockDef &def) +int CSVSettings::GroupBlock::build (GroupBlockDef *def) { - if (def.properties.size() == 0) + if (def->settingItems.size() == 0) return -1; int retVal = 0; - setVisible (def.isVisible); + setVisible (def->isVisible); - mBox->setLayout(createLayout (def.widgetOrientation, true)); + mBox->setLayout(createLayout (def->widgetOrientation, true)); - setObjectName (def.title); - mBox->setTitle (def.title); + setObjectName (def->title); + mBox->setTitle (def->title); - foreach (SettingsItemDef *itemDef, def.properties) + foreach (SettingsItemDef *itemDef, def->settingItems) { ItemBlock *block = new ItemBlock (mBox); diff --git a/apps/opencs/view/settings/groupblock.hpp b/apps/opencs/view/settings/groupblock.hpp index a8fd4e3b4..5c0754193 100644 --- a/apps/opencs/view/settings/groupblock.hpp +++ b/apps/opencs/view/settings/groupblock.hpp @@ -8,6 +8,8 @@ namespace CSVSettings { class ItemBlock; + /// Base class for group blocks. + /// Derived block classes should use CustomBlock class GroupBlock : public AbstractBlock { ItemBlockList mItemBlockList; @@ -16,15 +18,24 @@ namespace CSVSettings GroupBlock (QWidget* parent = 0); GroupBlock (bool isVisible, QWidget *parent = 0); - int build (GroupBlockDef &def); + /// build the gorup block based on passed definition + int build (GroupBlockDef *def); + /// update settings local to the group block bool updateSettings (const CSMSettings::SettingMap &settings); + /// retrieve setting list local to the group block CSMSettings::SettingList *getSettings(); + + /// retrieve item block by name from the passed list or local list ItemBlock *getItemBlock (const QString &name, ItemBlockList *blockList = 0); + + /// retrieve the item block by index from the local list ItemBlock *getItemBlock (int index); protected: + + /// create block layout based on passed definition int buildLayout (GroupBlockDef &def); }; diff --git a/apps/opencs/view/settings/groupbox.hpp b/apps/opencs/view/settings/groupbox.hpp index 43cb2e0c3..9d3a01936 100644 --- a/apps/opencs/view/settings/groupbox.hpp +++ b/apps/opencs/view/settings/groupbox.hpp @@ -5,6 +5,7 @@ namespace CSVSettings { + /// Custom implementation of QGroupBox to be used with block classes class GroupBox : public QGroupBox { static const QString INVISIBLE_BOX_STYLE; diff --git a/apps/opencs/view/settings/itemblock.hpp b/apps/opencs/view/settings/itemblock.hpp index c7714ac64..1a5447e31 100644 --- a/apps/opencs/view/settings/itemblock.hpp +++ b/apps/opencs/view/settings/itemblock.hpp @@ -15,22 +15,32 @@ namespace CSVSettings ItemBlock (QWidget* parent = 0); + /// pure virtual function not implemneted bool updateSettings (const CSMSettings::SettingMap &settings) { return false; } CSMSettings::SettingList *getSettings (); + QString getValue () const; + /// item blocks encapsulate only one setting int getSettingCount(); + + /// update setting value and corresponding widget bool update (const QString &value); + /// virtual construction function int build(SettingsItemDef &iDef); private: + /// custom construction function void buildItemBlock (SettingsItemDef& iDef); void buildItemBlockWidgets (SettingsItemDef& iDef); + + /// update the setting value bool updateItem (const QString &); + /// callback function triggered when update to application level is signalled bool updateBySignal (const QString &name, const QString &value, bool &doEmit); }; } diff --git a/apps/opencs/view/settings/proxyblock.cpp b/apps/opencs/view/settings/proxyblock.cpp index 71a307084..81cc54fca 100644 --- a/apps/opencs/view/settings/proxyblock.cpp +++ b/apps/opencs/view/settings/proxyblock.cpp @@ -5,10 +5,10 @@ CSVSettings::ProxyBlock::ProxyBlock (QWidget *parent) : GroupBlock (parent) { } -int CSVSettings::ProxyBlock::build (GroupBlockDef &proxyDef) +int CSVSettings::ProxyBlock::build (GroupBlockDef *proxyDef) { //get the list of pre-defined values for the proxy - mValueList = proxyDef.properties.at(0)->valueList; + mValueList = proxyDef->settingItems.at(0)->valueList; bool success = GroupBlock::build(proxyDef); @@ -53,6 +53,8 @@ bool CSVSettings::ProxyBlock::updateProxiedSettings() bool success = false; int i = 0; + + //find the value index of the selected value in the proxy setting for (; i < mValueList->size(); ++i) { success = (value == mValueList->at(i)); @@ -64,6 +66,7 @@ bool CSVSettings::ProxyBlock::updateProxiedSettings() if (!success) return false; + // update the containing the proxied item's name foreach (QStringList *list, mProxyList) { if ( list->at(0) == block->objectName()) diff --git a/apps/opencs/view/settings/proxyblock.hpp b/apps/opencs/view/settings/proxyblock.hpp index f757842ea..90fb9bc97 100644 --- a/apps/opencs/view/settings/proxyblock.hpp +++ b/apps/opencs/view/settings/proxyblock.hpp @@ -9,8 +9,7 @@ namespace CSVSettings { Q_OBJECT - //NOTE: mProxyItemBlockList and mProxyList - //should be combined into a value pair and stored in one list. + /// TODO: Combine mProxyItemBlockList and mProxyList. ItemBlockList mProxiedItemBlockList; ProxyList mProxyList; QStringList *mValueList; @@ -20,17 +19,28 @@ namespace CSVSettings explicit ProxyBlock (QWidget *parent = 0); explicit ProxyBlock (ItemBlock *proxyItemBlock, QWidget *parent = 0); + /// Add a block that contains a proxied setting to the proxy block. void addSetting (ItemBlock* settingBlock, QStringList *proxyList); - int build (GroupBlockDef &def); + + int build (GroupBlockDef *def); CSMSettings::SettingList *getSettings() { return 0; } + + /// Update settings local to the proxy block pushed from application level bool updateSettings (const CSMSettings::SettingMap &settings); + + /// callback function triggered when update to the application level is signaled. bool updateBySignal (const QString &name, const QString &value, bool &doEmit); private: + /// return the item block of a proxied setting ItemBlock *getProxiedItemBlock (const QString &name); + + /// update the proxy setting with data from the proxied settings bool updateByProxiedSettings(const CSMSettings::SettingMap *settings = 0); + + /// update proxied settings with data from the proxy setting bool updateProxiedSettings(); private slots: diff --git a/apps/opencs/view/settings/settingwidget.hpp b/apps/opencs/view/settings/settingwidget.hpp index b29523a3a..9f4513671 100644 --- a/apps/opencs/view/settings/settingwidget.hpp +++ b/apps/opencs/view/settings/settingwidget.hpp @@ -16,7 +16,8 @@ namespace CSVSettings { - //VALID FOR RADIOBUTTON / CHECKBOX (or other toggle widget with it's own label) + + /// Generic template for radiobuttons / checkboxes template class SettingWidget : public AbstractWidget { @@ -47,6 +48,7 @@ namespace CSVSettings } }; + /// spin box template template <> class SettingWidget : public AbstractWidget { @@ -90,6 +92,7 @@ namespace CSVSettings }; + /// combo box template template <> class SettingWidget : public CSVSettings::AbstractWidget { @@ -142,6 +145,7 @@ namespace CSVSettings }; + /// line edit template template <> class SettingWidget : public CSVSettings::AbstractWidget { @@ -175,6 +179,8 @@ namespace CSVSettings } }; + /// list widget template + /// \todo Not fully implemented. Only widget supporting multi-valued settings template <> class SettingWidget : public CSVSettings::AbstractWidget { diff --git a/apps/opencs/view/settings/support.hpp b/apps/opencs/view/settings/support.hpp index 7185d2706..1df0dac1e 100644 --- a/apps/opencs/view/settings/support.hpp +++ b/apps/opencs/view/settings/support.hpp @@ -44,21 +44,44 @@ namespace CSVSettings Align_Right = Qt::AlignRight }; - //template for defining the widget of a property. + /// definition struct for widgets struct WidgetDef { - WidgetType type; //type of widget providing input - int labelWidth; //width of caption label - int widgetWidth; //width of input widget - Orientation orientation; //label / widget orientation (horizontal / vertical) - QString inputMask; //input mask (line edit) - QString caption; //label caption. Leave empty for multiple items. See BlockDef::captionList - QString value; //widget value. Leave empty for multiple items. See BlockDef::valueList - CSMSettings::QStringPair *minMax; //Min/Max QString value pair. If empty, assigned to property item value pair. - QStringList *valueList; //value list for list widgets. If left empty, is assigned to property item value list during block build(). - bool isDefault; //isDefault - determined at runtime. - Alignment valueAlignment; //left / center / right-justify text in widget - Alignment widgetAlignment; //left / center / right-justify widget in group box + /// type of widget providing input + WidgetType type; + + /// width of caption label + int labelWidth; + + /// width of input widget + int widgetWidth; + + /// label / widget orientation (horizontal / vertical) + Orientation orientation; + + /// input mask (line edit only) + QString inputMask; + + /// label caption. Leave empty for multiple items. See BlockDef::captionList + QString caption; + + /// widget value. Leave empty for multiple items. See BlockDef::valueList + QString value; + + /// Min/Max QString value pair. If empty, assigned to property item value pair. + CSMSettings::QStringPair *minMax; + + /// value list for list widgets. If left empty, is assigned to property item value list during block build(). + QStringList *valueList; + + /// determined at runtime + bool isDefault; + + /// left / center / right-justify text in widget + Alignment valueAlignment; + + /// left / center / right-justify widget in group box + Alignment widgetAlignment; WidgetDef() : labelWidth (-1), widgetWidth (-1), @@ -79,20 +102,34 @@ namespace CSVSettings }; - //Defines the attributes of the property as it is represented in the config file - //as well as the UI elements (group box and widget) that serve it. - //Only one widget may serve as the input widget for the property. + /// Defines the attributes of the setting as it is represented in the config file + /// as well as the UI elements (group box and widget) that serve it. + /// Only one widget may serve as the input widget for the setting. struct SettingsItemDef { - QString name; //property name - QStringList *valueList; //list of valid values for the property. - //Used to populate option widget captions or list widget item lists (see WidgetDef::caption / value) + /// setting name + QString name; + + /// list of valid values for the setting + QStringList *valueList; + + /// Used to populate option widget captions or list widget item lists (see WidgetDef::caption / value) QString defaultValue; + + /// flag indicating multi-valued setting bool hasMultipleValues; - CSMSettings::QStringPair minMax; //minimum / maximum value pair - WidgetDef widget; //definition of the input widget for this setting - Orientation orientation; //general orientation of the widget / label for this property - ProxyList *proxyList; //list of property and corresponding default values for proxy widget + + /// minimum / maximum value pair + CSMSettings::QStringPair minMax; + + /// definition of the input widget for this setting + WidgetDef widget; + + /// general orientation of the widget / label for this setting + Orientation orientation; + + /// list of settings and corresponding default values for proxy widget + ProxyList *proxyList; SettingsItemDef() : name (""), defaultValue (""), orientation (Orient_Vertical), hasMultipleValues (false) {} @@ -104,18 +141,32 @@ namespace CSVSettings }; - //Hierarchically, this is a "sub-section" of properties within a section, solely for UI organization. - //Does not correlate to config file structure. + /// Generic container block struct GroupBlockDef { - QString title; //title of the block containing the property or properties of this sub-section - QStringList captions; //list of captions for widgets at the block level (not associated with any particular property) - WidgetList widgets; //list of widgets at the block level (not associated with any particular property) - QList properties; //list of the property(ies) which are subordinate to the property block. - Orientation widgetOrientation; //general orientation of widgets in group block - bool isVisible; //determines whether or not box border/title are visible - bool isProxy; //indicates whether or not this block defines a proxy block - QString defaultValue; //generic default value attribute + /// block title + QString title; + + /// list of captions for widgets at the block level (not associated with any particular setting) + QStringList captions; + + /// list of widgets at the block level (not associated with any particular setting) + WidgetList widgets; + + /// list of the settings which are subordinate to the setting block. + QList settingItems; + + /// general orientation of widgets in group block + Orientation widgetOrientation; + + /// determines whether or not box border/title are visible + bool isVisible; + + /// indicates whether or not this block defines a proxy block + bool isProxy; + + /// generic default value attribute + QString defaultValue; GroupBlockDef (): title(""), widgetOrientation (Orient_Vertical), isVisible (true), isProxy (false), defaultValue ("") {} @@ -125,11 +176,19 @@ namespace CSVSettings {} }; + /// used to create unique, complex blocks struct CustomBlockDef { + /// block title QString title; - QString defaultValue; //default value for widgets unique to the custom block - GroupBlockDefList blockDefList; //list of settings groups that comprise the settings within the custom block + + /// default value for widgets unique to the custom block + QString defaultValue; + + /// list of settings groups that comprise the settings within the custom block + GroupBlockDefList blockDefList; + + /// orientation of the widgets within the block Orientation blockOrientation; CustomBlockDef (): title (""), defaultValue (""), blockOrientation (Orient_Horizontal) diff --git a/apps/opencs/view/settings/toggleblock.cpp b/apps/opencs/view/settings/toggleblock.cpp index 12a42ca9c..3406a62c4 100644 --- a/apps/opencs/view/settings/toggleblock.cpp +++ b/apps/opencs/view/settings/toggleblock.cpp @@ -7,24 +7,24 @@ CSVSettings::ToggleBlock::ToggleBlock(QWidget *parent) : CustomBlock(parent) {} -int CSVSettings::ToggleBlock::build(CustomBlockDef &def) +int CSVSettings::ToggleBlock::build(CustomBlockDef *def) { - if (def.blockDefList.size()==0) + if (def->blockDefList.size()==0) return -1; - QList::Iterator it = def.blockDefList.begin(); + QList::Iterator it = def->blockDefList.begin(); //first def in the list is the def for the toggle block GroupBlockDef *toggleDef = *it++; - if (toggleDef->captions.size() != def.blockDefList.size()-1 ) + if (toggleDef->captions.size() != def->blockDefList.size()-1 ) return -2; if (toggleDef->widgets.size() == 0) return -3; //create the toogle block UI structure - QLayout *blockLayout = createLayout (def.blockOrientation, true); + QLayout *blockLayout = createLayout (def->blockOrientation, true); GroupBox *propertyBox = buildGroupBox (toggleDef->widgetOrientation); mBox->setLayout(blockLayout); @@ -34,13 +34,13 @@ int CSVSettings::ToggleBlock::build(CustomBlockDef &def) //this manages proxy block construction. //Any settings managed by the proxy setting //must be included in the blocks defined in the list. - CustomBlock::build (def.blockDefList, &it); + CustomBlock::build (def->blockDefList, &it); for (GroupBlockList::iterator it = mGroupList.begin(); it != mGroupList.end(); ++it) propertyBox->layout()->addWidget ((*it)->getGroupBox()); //build togle widgets, linking them to the settings - GroupBox *toggleBox = buildToggleWidgets (*toggleDef, def.defaultValue); + GroupBox *toggleBox = buildToggleWidgets (toggleDef, def->defaultValue); blockLayout->addWidget(toggleBox); blockLayout->addWidget(propertyBox); @@ -49,16 +49,16 @@ int CSVSettings::ToggleBlock::build(CustomBlockDef &def) return 0; } -CSVSettings::GroupBox *CSVSettings::ToggleBlock::buildToggleWidgets (GroupBlockDef &def, QString &defaultToggle) +CSVSettings::GroupBox *CSVSettings::ToggleBlock::buildToggleWidgets (GroupBlockDef *def, QString &defaultToggle) { GroupBox *box = new GroupBox (false, getParent()); - QLayout *layout = createLayout (def.widgetOrientation, true, static_cast(box)); + QLayout *layout = createLayout (def->widgetOrientation, true, static_cast(box)); - for (int i = 0; i < def.widgets.size(); ++i) + for (int i = 0; i < def->widgets.size(); ++i) { - QString caption = def.captions.at(i); - WidgetDef *wDef = def.widgets.at(i); + QString caption = def->captions.at(i); + WidgetDef *wDef = def->widgets.at(i); wDef->caption = caption; wDef->widgetAlignment = Align_Left; diff --git a/apps/opencs/view/settings/toggleblock.hpp b/apps/opencs/view/settings/toggleblock.hpp index 8afe701b8..4b6e8e344 100644 --- a/apps/opencs/view/settings/toggleblock.hpp +++ b/apps/opencs/view/settings/toggleblock.hpp @@ -18,10 +18,12 @@ namespace CSVSettings public: explicit ToggleBlock(QWidget *parent = 0); - int build (CustomBlockDef &def); + int build (CustomBlockDef *def); private: - GroupBox *buildToggleWidgets (GroupBlockDef &def, QString &defaultToggle); + /// Constructor for toggle widgets that are specific to toggle block + /// Widgets are not a part of the user preference settings + GroupBox *buildToggleWidgets (GroupBlockDef *def, QString &defaultToggle); }; } #endif // TOGGLEBLOCK_HPP diff --git a/apps/opencs/view/settings/usersettingsdialog.cpp b/apps/opencs/view/settings/usersettingsdialog.cpp index 012fc0408..64b9aacff 100644 --- a/apps/opencs/view/settings/usersettingsdialog.cpp +++ b/apps/opencs/view/settings/usersettingsdialog.cpp @@ -10,25 +10,26 @@ #include #include -#include "blankpage.hpp" -#include "editorpage.hpp" -#include "../../model/settings/support.hpp" +#include +#include "editorpage.hpp" +#include "windowpage.hpp" + +#include "../../model/settings/support.hpp" +#include #include "settingwidget.hpp" -#include CSVSettings::UserSettingsDialog::UserSettingsDialog(QMainWindow *parent) : QMainWindow (parent), mStackedWidget (0) { setWindowTitle(QString::fromUtf8 ("User Settings")); buildPages(); - setWidgetStates (loadSettings()); - positionWindow (); + setWidgetStates (); connect (mListWidget, SIGNAL (currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, - SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); + SLOT (slotChangePage (QListWidgetItem*, QListWidgetItem*))); } CSVSettings::UserSettingsDialog::~UserSettingsDialog() @@ -40,17 +41,21 @@ void CSVSettings::UserSettingsDialog::closeEvent (QCloseEvent *event) writeSettings(); } -void CSVSettings::UserSettingsDialog::setWidgetStates (CSMSettings::SectionMap settingsMap) +void CSVSettings::UserSettingsDialog::setWidgetStates () { + CSMSettings::UserSettings::instance().loadSettings("opencs.cfg"); + const CSMSettings::SectionMap §ionSettings = CSMSettings::UserSettings::instance().getSettings(); + //iterate the tabWidget's pages (sections) for (int i = 0; i < mStackedWidget->count(); i++) { //get the settings defined for the entire section - CSMSettings::SettingMap *settings = settingsMap [mStackedWidget->widget(i)->objectName()]; + //and update widget + QString pageName = mStackedWidget->widget(i)->objectName(); - //if found, initialize the page's widgets - if (settings) + if (sectionSettings.find(pageName) != sectionSettings.end()) { + CSMSettings::SettingMap *settings = sectionSettings.value(pageName); AbstractPage *page = getAbstractPage (i); page->initializeWidgets(*settings); } @@ -65,83 +70,24 @@ void CSVSettings::UserSettingsDialog::buildPages() mListWidget = new QListWidget (centralWidget); mStackedWidget = new QStackedWidget (centralWidget); - QLayout* dialogLayout = new QHBoxLayout(); + QGridLayout* dialogLayout = new QGridLayout(); - dialogLayout->addWidget (mListWidget); - dialogLayout->addWidget (mStackedWidget); + mListWidget->setMinimumWidth(0); + mListWidget->setSizePolicy (QSizePolicy::Preferred, QSizePolicy::Expanding); + + mStackedWidget->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + + dialogLayout->addWidget (mListWidget,0,0); + dialogLayout->addWidget (mStackedWidget,0,1, Qt::AlignTop); centralWidget->setLayout (dialogLayout); setCentralWidget (centralWidget); setDockOptions (QMainWindow::AllowNestedDocks); - //uncomment to test with sample editor page. - //createSamplePage(); - createPage("Page1"); - createPage("Page2"); - createPage("Page3"); -} -void CSVSettings::UserSettingsDialog::createSamplePage() -{ - //add pages to stackedwidget and items to listwidget - CSVSettings::AbstractPage *page - = new CSVSettings::EditorPage(this); + createPage(); + createPage(); - mStackedWidget->addWidget (page); - - new QListWidgetItem (page->objectName(), mListWidget); - - connect ( page, SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)), - &(CSMSettings::UserSettings::instance()), SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &))); -} - -void CSVSettings::UserSettingsDialog::positionWindow () -{ - QRect scr = QApplication::desktop()->screenGeometry(); - - move(scr.center().x() - (width() / 2), scr.center().y() - (height() / 2)); - -} - -CSMSettings::SectionMap CSVSettings::UserSettingsDialog::loadSettings () -{ - QString userPath = QString::fromStdString(mCfgMgr.getUserPath().string()); - - mPaths.append(QString("opencs.cfg")); - mPaths.append(userPath + QString("opencs.cfg")); - - CSMSettings::SectionMap settingsMap; - - foreach (const QString &path, mPaths) - { - qDebug() << "Loading config file:" << qPrintable(path); - QFile file(path); - - if (file.exists()) - { - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QMessageBox msgBox; - msgBox.setWindowTitle(tr("Error opening OpenCS configuration file")); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(QObject::tr("
Could not open %0 for reading

\ - Please make sure you have the right permissions \ - and try again.
").arg(file.fileName())); - msgBox.exec(); - return settingsMap; - } - - QTextStream stream(&file); - stream.setCodec(QTextCodec::codecForName("UTF-8")); - - CSMSettings::UserSettings::instance().getSettings(stream, settingsMap); - } - - file.close(); - } - - return settingsMap; } void CSVSettings::UserSettingsDialog::writeSettings() @@ -153,9 +99,7 @@ void CSVSettings::UserSettingsDialog::writeSettings() AbstractPage *page = getAbstractPage (i); settings [page->objectName()] = page->getSettings(); } - - CSMSettings::UserSettings::instance().writeFile(CSMSettings::UserSettings::instance().openFile(mPaths.back()), settings); - + CSMSettings::UserSettings::instance().writeSettings(settings); } CSVSettings::AbstractPage *CSVSettings::UserSettingsDialog::getAbstractPage (int index) diff --git a/apps/opencs/view/settings/usersettingsdialog.hpp b/apps/opencs/view/settings/usersettingsdialog.hpp index 31d40ca01..a992dbdf8 100644 --- a/apps/opencs/view/settings/usersettingsdialog.hpp +++ b/apps/opencs/view/settings/usersettingsdialog.hpp @@ -4,14 +4,13 @@ #include #include #include - -#ifndef Q_MOC_RUN -#include -#endif +#include #include "../../model/settings/usersettings.hpp" #include "../../model/settings/support.hpp" +#include "editorpage.hpp" + class QHBoxLayout; class AbstractWidget; class QStackedWidget; @@ -25,10 +24,8 @@ namespace CSVSettings { { Q_OBJECT - QStringList mPaths; QListWidget *mListWidget; QStackedWidget *mStackedWidget; - Files::ConfigurationManager mCfgMgr; public: UserSettingsDialog(QMainWindow *parent = 0); @@ -36,35 +33,39 @@ namespace CSVSettings { private: + /// Settings are written on close void closeEvent (QCloseEvent *event); - AbstractPage *getAbstractPage (int index); - void setWidgetStates (CSMSettings::SectionMap settingsMap); - void buildPages(); - void positionWindow (); - CSMSettings::SectionMap loadSettings(); - void writeSettings(); - void createSamplePage(); + /// return the setting page by name + /// performs dynamic cast to AbstractPage * + AbstractPage *getAbstractPage (int index); + void setWidgetStates (); + void buildPages(); + void writeSettings(); + + /// Templated function to create a custom user preference page template - void createPage (const QString &title) + void createPage () { - T *page = new T(title, this); + T *page = new T(mStackedWidget); mStackedWidget->addWidget (dynamic_cast(page)); new QListWidgetItem (page->objectName(), mListWidget); //finishing touches - if (mStackedWidget->sizeHint().width() < 640) - mStackedWidget->sizeHint().setWidth(640); + QFontMetrics fm (QApplication::font()); + int textWidth = fm.width(page->objectName()); - if (mStackedWidget->sizeHint().height() < 480) - mStackedWidget->sizeHint().setHeight(480); + if ((textWidth + 50) > mListWidget->minimumWidth()) + mListWidget->setMinimumWidth(textWidth + 50); resize (mStackedWidget->sizeHint()); } public slots: + + /// Called when a different page is selected in the left-hand list widget void slotChangePage (QListWidgetItem*, QListWidgetItem*); }; diff --git a/apps/opencs/view/settings/windowpage.cpp b/apps/opencs/view/settings/windowpage.cpp new file mode 100644 index 000000000..42d72cf75 --- /dev/null +++ b/apps/opencs/view/settings/windowpage.cpp @@ -0,0 +1,144 @@ +#include "windowpage.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_MAC +#include +#endif + +#include "../../model/settings/usersettings.hpp" +#include "groupblock.hpp" +#include "toggleblock.hpp" +#include "../../view/settings/abstractblock.hpp" + +CSVSettings::WindowPage::WindowPage(QWidget *parent): + AbstractPage("Window", parent) +{ + // Hacks to get the stylesheet look properly +#ifdef Q_OS_MAC + QPlastiqueStyle *style = new QPlastiqueStyle; + //profilesComboBox->setStyle(style); +#endif + + setupUi(); +} + +CSVSettings::GroupBlockDef * CSVSettings::WindowPage::buildDefinedWindowSize() +{ + GroupBlockDef *block = new GroupBlockDef ( "Defined Size"); + + SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480"); + WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox); + widthByHeightWidget.widgetWidth = 90; + *(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768" << "1440x900"; + + QStringList *widthProxy = new QStringList; + QStringList *heightProxy = new QStringList; + + (*widthProxy) << "Width" << "640" << "800" << "1024" << "1440"; + (*heightProxy) << "Height" << "480" << "600" << "768" << "900"; + + *(widthByHeightItem->proxyList) << widthProxy << heightProxy; + + widthByHeightItem->widget = widthByHeightWidget; + + block->settingItems << widthByHeightItem; + block->isProxy = true; + block->isVisible = false; + + return block; +} + +CSVSettings::GroupBlockDef *CSVSettings::WindowPage::buildCustomWindowSize() +{ + GroupBlockDef *block = new GroupBlockDef ("Custom Size"); + + //custom width + SettingsItemDef *widthItem = new SettingsItemDef ("Width", "640"); + widthItem->widget = WidgetDef (Widget_LineEdit); + widthItem->widget.widgetWidth = 45; + widthItem->widget.inputMask = "9999"; + + //custom height + SettingsItemDef *heightItem = new SettingsItemDef ("Height", "480"); + heightItem->widget = WidgetDef (Widget_LineEdit); + heightItem->widget.widgetWidth = 45; + heightItem->widget.caption = "x"; + heightItem->widget.inputMask = "9999"; + + block->settingItems << widthItem << heightItem; + block->widgetOrientation = Orient_Horizontal; + block->isVisible = false; + + return block; +} + +CSVSettings::GroupBlockDef *CSVSettings::WindowPage::buildWindowSizeToggle() +{ + GroupBlockDef *block = new GroupBlockDef ("Window Size"); + + // window size toggle + block->captions << "Pre-Defined" << "Custom"; + block->widgetOrientation = Orient_Vertical; + block->isVisible = false; + + //define a widget for each group in the toggle + for (int i = 0; i < 2; i++) + block->widgets << new WidgetDef (Widget_RadioButton); + + block->widgets.at(0)->isDefault = false; + + return block; +} + +CSVSettings::CustomBlockDef *CSVSettings::WindowPage::buildWindowSize(GroupBlockDef *toggle_def, + GroupBlockDef *defined_def, + GroupBlockDef *custom_def) +{ + CustomBlockDef *block = new CustomBlockDef(QString ("Window Size")); + + block->blockDefList << toggle_def << defined_def << custom_def; + block->defaultValue = "Custom"; + + return block; + +} + +void CSVSettings::WindowPage::setupUi() +{ + CustomBlockDef *windowSize = buildWindowSize(buildWindowSizeToggle(), + buildDefinedWindowSize(), + buildCustomWindowSize() + ); + + mAbstractBlocks << buildBlock (windowSize); + + foreach (AbstractBlock *block, mAbstractBlocks) + { + connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)), + this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) ); + } + + connect ( this, + SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &)), + &(CSMSettings::UserSettings::instance()), + SIGNAL ( signalUpdateEditorSetting (const QString &, const QString &))); + +} + + +void CSVSettings::WindowPage::initializeWidgets (const CSMSettings::SettingMap &settings) +{ + //iterate each item in each blocks in this section + //validate the corresponding setting against the defined valuelist if any. + for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin(); + it_block != mAbstractBlocks.end(); ++it_block) + (*it_block)->updateSettings (settings); +} diff --git a/apps/opencs/view/settings/windowpage.hpp b/apps/opencs/view/settings/windowpage.hpp new file mode 100644 index 000000000..2f2830625 --- /dev/null +++ b/apps/opencs/view/settings/windowpage.hpp @@ -0,0 +1,34 @@ +#ifndef WINDOWPAGE_H +#define WINDOWPAGE_H + +#include "abstractpage.hpp" + +class QGroupBox; + +namespace CSVSettings { + + class UserSettings; + class AbstractBlock; + + class WindowPage : public AbstractPage + { + Q_OBJECT + + public: + + WindowPage(QWidget *parent = 0); + + void setupUi(); + void initializeWidgets (const CSMSettings::SettingMap &settings); + + /// + GroupBlockDef *buildCustomWindowSize(); + GroupBlockDef *buildDefinedWindowSize(); + GroupBlockDef *buildWindowSizeToggle(); + CustomBlockDef *buildWindowSize (GroupBlockDef *, GroupBlockDef *, GroupBlockDef *); + + signals: + void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); + }; +} +#endif //WINDOWPAGE_H diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp new file mode 100644 index 000000000..243f509ef --- /dev/null +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -0,0 +1,122 @@ +#include "recordstatusdelegate.hpp" +#include +#include +#include +#include "../../model/settings/usersettings.hpp" + +CSVWorld::RecordStatusDelegate::RecordStatusDelegate(QUndoStack &undoStack, QObject *parent) + : CommandDelegate (undoStack, parent) +{ + mModifiedIcon = new QIcon (":./modified.png"); + mAddedIcon = new QIcon (":./added.png"); + mDeletedIcon = new QIcon (":./removed.png"); + mBaseIcon = new QIcon (":./base.png"); + mIconSize = 16; + + //Offset values are most likely device-dependent. + //Need to replace with device-independent references. + mTextLeftOffset = 3; + mIconTopOffset = -3; + + mStatusDisplay = 0; //icons and text by default. Remove when implemented as a user preference + + mFont = QApplication::font(); + mFont.setPointSize(10); + + mFontMetrics = new QFontMetrics(mFont); + + mTextAlignment.setAlignment (Qt::AlignLeft | Qt::AlignVCenter ); +} + +void CSVWorld::RecordStatusDelegate::paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + painter->save(); + + QString text = ""; + QIcon *icon = 0; + + switch (index.data().toInt()) + { + case 0: // State_BaseOnly + text = "Base"; + icon = mBaseIcon; + break; + + case 1: // State_Modified + text = "Modified"; + icon = mModifiedIcon; + break; + + case 2: // State_Modified_Only + text = "Added"; + icon = mAddedIcon; + break; + + case 3: // State_Deleted + + case 4: // State_Erased + text = "Deleted"; + icon = mDeletedIcon; + break; + + default: + break; + } + + QRect textRect = option.rect; + QRect iconRect = option.rect; + + //for icon-only (1), default option.rect centers icon left-to-right + //otherwise, size option.rect to fit the icon, forcing left-alignment with text + iconRect.setTop (iconRect.top() + mIconTopOffset); + iconRect.setBottom (iconRect.top() + mIconSize); + + if (mStatusDisplay == 0 && (icon) ) + { + iconRect.setRight (iconRect.left()+ mIconSize*2); + textRect.setLeft (iconRect.right() + mTextLeftOffset *1.25); + } + else + textRect.setLeft (textRect.left() + mTextLeftOffset ); + + if ( (mStatusDisplay == 0 || mStatusDisplay == 1) && (icon) ) + painter->drawPixmap(iconRect.center().x()-10,iconRect.center().y()+2, icon->pixmap(mIconSize, mIconSize)); + + // icon + text or text only, or force text if no icon exists for status + if (mStatusDisplay == 0 || mStatusDisplay == 2 || !(icon) ) + { + painter->setFont(mFont); + painter->drawText(textRect, text, mTextAlignment); + } + + painter->restore(); +} + +QSize CSVWorld::RecordStatusDelegate::sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + return QSize(); +} + +CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate (QUndoStack& undoStack, + QObject *parent) const +{ + return new RecordStatusDelegate (undoStack, parent); +} + +void CSVWorld::RecordStatusDelegate::updateEditorSetting (const QString &settingName, const QString &settingValue) +{ + if (settingName == "Record Status Display") + { + if (settingValue == "Icon and Text") + mStatusDisplay = 0; + + else if (settingValue == "Icon Only") + mStatusDisplay = 1; + + else if (settingValue == "Text Only") + mStatusDisplay = 2; + + else + mStatusDisplay = 0; + } +} diff --git a/apps/opencs/view/world/recordstatusdelegate.hpp b/apps/opencs/view/world/recordstatusdelegate.hpp new file mode 100644 index 000000000..b67226ad5 --- /dev/null +++ b/apps/opencs/view/world/recordstatusdelegate.hpp @@ -0,0 +1,53 @@ +#ifndef RECORDSTATUSDELEGATE_H +#define RECORDSTATUSDELEGATE_H + +#include "util.hpp" +#include +#include + +class QIcon; +class QFont; +class QFontMetrics; + +namespace CSVWorld +{ + class RecordStatusDelegate : public CommandDelegate + { + QFont mFont; + QFontMetrics *mFontMetrics; + + QTextOption mTextAlignment; + + QIcon *mModifiedIcon; + QIcon *mAddedIcon; + QIcon *mDeletedIcon; + QIcon *mBaseIcon; + + int mStatusDisplay; + + int mIconSize; + int mIconTopOffset; + int mTextLeftOffset; + + public: + explicit RecordStatusDelegate(QUndoStack& undoStack, QObject *parent = 0); + + void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + + QSize sizeHint (const QStyleOptionViewItem &option, const QModelIndex &index) const; + + void updateEditorSetting (const QString &settingName, const QString &settingValue); + + }; + + class RecordStatusDelegateFactory : public CommandDelegateFactory + { + public: + + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; + ///< The ownership of the returned CommandDelegate is transferred to the caller. + + }; +} +#endif // RECORDSTATUSDELEGATE_H + diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index f9167d259..1ec0dde09 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -12,6 +12,7 @@ #include "../../model/world/idtableproxymodel.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/record.hpp" +#include "recordstatusdelegate.hpp" #include "util.hpp" @@ -80,7 +81,7 @@ std::vector CSVWorld::Table::listDeletableSelectedIds() const CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete) -: mUndoStack (undoStack), mCreateAction (0), mEditLock (false) + : mUndoStack (undoStack), mCreateAction (0), mEditLock (false), mRecordStatusDisplay (0) { mModel = &dynamic_cast (*data.getTableModel (id)); @@ -161,6 +162,7 @@ void CSVWorld::Table::createRecord() mUndoStack.push (new CSMWorld::CreateCommand (*mProxyModel, stream.str())); } + } void CSVWorld::Table::revertRecord() @@ -201,4 +203,13 @@ void CSVWorld::Table::deleteRecord() mUndoStack.endMacro(); } } -} \ No newline at end of file +} + +void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue) +{ + if (settingName == "Record Status Display") + { + dynamic_cast(this->itemDelegateForColumn(1))->updateEditorSetting (settingName, settingValue); + emit dataChanged(mModel->index(0,1), mModel->index(mModel->rowCount()-1, 1)); + } +} diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index df0224583..348e800cf 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -34,6 +34,7 @@ namespace CSVWorld CSMWorld::IdTableProxyModel *mProxyModel; CSMWorld::IdTable *mModel; bool mEditLock; + int mRecordStatusDisplay; private: @@ -52,6 +53,8 @@ namespace CSVWorld CSMWorld::UniversalId getUniversalId (int row) const; + void updateEditorSetting (const QString &settingName, const QString &settingValue); + private slots: void createRecord(); diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index bb4bb76c6..d139ef74b 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -22,4 +22,11 @@ void CSVWorld::TableSubView::setEditLock (bool locked) void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) { focusId (mTable->getUniversalId (index.row())); -} \ No newline at end of file +} + +void CSVWorld::TableSubView::updateEditorSetting(const QString &settingName, const QString &settingValue) +{ + + if (settingName == "Record Status Display") + mTable->updateEditorSetting(settingName, settingValue); +} diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index 0e7b8aa30..13db8255a 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -23,8 +23,8 @@ namespace CSVWorld public: TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, bool createAndDelete); - virtual void setEditLock (bool locked); + void updateEditorSetting (const QString &, const QString &); private slots: @@ -32,4 +32,4 @@ namespace CSVWorld }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index 95dfec6c5..251564e96 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -82,6 +82,8 @@ namespace CSVWorld ///< \brief Use commands instead of manipulating the model directly class CommandDelegate : public QStyledItemDelegate { + Q_OBJECT + QUndoStack& mUndoStack; bool mEditLock; @@ -105,6 +107,10 @@ namespace CSVWorld void setEditLock (bool locked); bool isEditLocked() const; + + private slots: + + virtual void slotUpdateEditorSetting (const QString &settingName, const QString &settingValue) {} }; } diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 660e45115..eebecc09c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -33,7 +33,7 @@ add_openmw_dir (mwgui enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview - tradeitemmodel companionitemmodel pickpocketitemmodel + tradeitemmodel companionitemmodel pickpocketitemmodel fontloader controllers ) add_openmw_dir (mwdialogue @@ -106,19 +106,23 @@ target_link_libraries(openmw ${OGRE_LIBRARIES} ${OGRE_Terrain_LIBRARY} ${OGRE_STATIC_PLUGINS} - ${OIS_LIBRARIES} ${Boost_LIBRARIES} ${OPENAL_LIBRARY} ${SOUND_INPUT_LIBRARY} ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} + ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} - "shiny" - "shiny.OgrePlatform" + ${SHINY_LIBRARIES} "oics" + "sdl4ogre" components ) +if (NOT UNIX) +target_link_libraries(openmw ${SDL2MAIN_LIBRARY}) +endif() + # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) @@ -131,10 +135,9 @@ endif() if(APPLE) - find_library(CARBON_FRAMEWORK Carbon) find_library(COCOA_FRAMEWORK Cocoa) find_library(IOKIT_FRAMEWORK IOKit) - target_link_libraries(openmw ${CARBON_FRAMEWORK} ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) + target_link_libraries(openmw ${COCOA_FRAMEWORK} ${IOKIT_FRAMEWORK}) if (FFMPEG_FOUND) find_library(COREVIDEO_FRAMEWORK CoreVideo) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index abc951726..2918f5d8b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,4 +1,5 @@ #include "engine.hpp" + #include "components/esm/loadcell.hpp" #include @@ -37,6 +38,8 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" +#include + void OMW::Engine::executeLocalScripts() { MWWorld::LocalScripts& localScripts = MWBase::Environment::get().getWorld()->getLocalScripts(); @@ -75,7 +78,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) try { float frametime = std::min(evt.timeSinceLastFrame, 0.2f); - mEnvironment.setFrameDuration(frametime); + + mEnvironment.setFrameDuration (frametime); // update input MWBase::Environment::get().getInputManager()->update(frametime, false); @@ -129,7 +133,6 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) , mFpsLevel(0) - , mDebug (false) , mVerboseScripts (false) , mNewGame (false) , mUseSound (true) @@ -141,6 +144,18 @@ 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("Could not initialize SDL! " + std::string(SDL_GetError())); + } + } } OMW::Engine::~Engine() @@ -148,6 +163,7 @@ OMW::Engine::~Engine() mEnvironment.cleanup(); delete mScriptContext; delete mOgre; + SDL_Quit(); } // Load BSA files @@ -268,11 +284,6 @@ void OMW::Engine::addPlugin (const std::string& plugin) } } -void OMW::Engine::setDebugMode(bool debugMode) -{ - mDebug = debugMode; -} - void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) { mVerboseScripts = scriptsVerbosity; @@ -315,6 +326,8 @@ 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); + return settingspath; } @@ -352,14 +365,16 @@ 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"); windowSettings.window_y = settings.getInt("resolution y", "Video"); + windowSettings.screen = settings.getInt("screen", "Video"); windowSettings.vsync = settings.getBool("vsync", "Video"); + windowSettings.icon = "openmw.png"; 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(); @@ -380,7 +395,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWindowManager (new MWGui::WindowManager( mExtensions, mFpsLevel, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), - mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage)); + mCfgMgr.getCachePath ().string(), mScriptConsoleMode, mTranslationDataStorage, mEncoding)); if (mNewGame) mEnvironment.getWindowManager()->setNewGame(true); @@ -409,7 +424,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)); mEnvironment.getWorld()->renderPlayer(); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index f80b67a35..665b0094c 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -71,7 +71,6 @@ namespace OMW std::vector mMaster; std::vector mPlugins; int mFpsLevel; - bool mDebug; bool mVerboseScripts; bool mNewGame; bool mUseSound; @@ -147,10 +146,6 @@ namespace OMW /// Enable fps counter void showFPS(int level); - /// Enable debug mode: - /// - non-exclusive input - void setDebugMode(bool debugMode); - /// Enable or disable verbose script output void setScriptsVerbosity(bool scriptsVerbosity); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 1fa461c2f..f11d153b4 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -2,6 +2,7 @@ #include +#include #include "engine.hpp" #if defined(_WIN32) && !defined(_CONSOLE) @@ -118,9 +119,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("anim-verbose", bpo::value()->implicit_value(true) ->default_value(false), "output animation indices files") - ("debug", bpo::value()->implicit_value(true) - ->default_value(false), "debug mode") - ("nosound", bpo::value()->implicit_value(true) ->default_value(false), "disable all sounds") @@ -217,8 +215,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat StringsVector master = variables["master"].as(); if (master.empty()) { - std::cout << "No master file given. Assuming Morrowind.esm" << std::endl; - master.push_back("Morrowind"); + std::cout << "No master file given. Aborting...\n"; + return false; } StringsVector plugin = variables["plugin"].as(); @@ -243,7 +241,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setNewGame(variables["new-game"].as()); // other settings - engine.setDebugMode(variables["debug"].as()); engine.setSoundUsage(!variables["nosound"].as()); engine.setScriptsVerbosity(variables["script-verbose"].as()); engine.setCompileAll(variables["script-all"].as()); diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 38794269b..7e09f9b4d 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -112,6 +112,8 @@ namespace MWBase virtual void skipAnimation(const MWWorld::Ptr& ptr) = 0; ///< Skip the animation for the given MW-reference for one frame. Calls to this function for /// references that are currently not in the scene should be ignored. + + virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) = 0; }; } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index ecea548a5..36d4ab8bb 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -55,6 +55,11 @@ namespace MWGui class DialogueWindow; } +namespace SFO +{ + class CursorManager; +} + namespace MWBase { /// \brief Interface for widnow manager (implemented in MWGui) @@ -92,6 +97,7 @@ namespace MWBase virtual void updatePlayer() = 0; virtual MWGui::GuiMode getMode() const = 0; + virtual bool containsMode(MWGui::GuiMode) const = 0; virtual bool isGuiMode() const = 0; @@ -159,7 +165,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; @@ -258,6 +264,8 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; + + virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index de1a34792..cf41f97df 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -342,6 +342,10 @@ namespace MWBase virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out) = 0; ///< get all containers in active cells owned by this Npc + virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out) = 0; + ///< get all items in active cells owned by this Npc + + virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0; virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index a4eda7126..a263af464 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -5,6 +5,7 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/magiceffects.hpp" +#include "../mwmechanics/movement.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" @@ -29,6 +30,7 @@ namespace { MWMechanics::CreatureStats mCreatureStats; MWWorld::ContainerStore mContainerStore; + MWMechanics::Movement mMovement; virtual MWWorld::CustomData *clone() const; }; @@ -47,6 +49,18 @@ namespace MWClass { std::auto_ptr data (new CustomData); + static bool inited = false; + if(!inited) + { + const MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + + fMinWalkSpeedCreature = gmst.find("fMinWalkSpeedCreature"); + fMaxWalkSpeedCreature = gmst.find("fMaxWalkSpeedCreature"); + + inited = true; + } + MWWorld::LiveCellRef *ref = ptr.get(); // creature stats @@ -181,6 +195,42 @@ namespace MWClass return true; } + float Creature::getSpeed(const MWWorld::Ptr &ptr) const + { + MWMechanics::CreatureStats& stats = getCreatureStats(ptr); + float walkSpeed = fMinWalkSpeedCreature->getFloat() + 0.01 * stats.getAttribute(ESM::Attribute::Speed).getModified() + * (fMaxWalkSpeedCreature->getFloat() - fMinWalkSpeedCreature->getFloat()); + /// \todo what about the rest? + return walkSpeed; + } + + MWMechanics::Movement& Creature::getMovementSettings (const MWWorld::Ptr& ptr) const + { + ensureCustomData (ptr); + + return dynamic_cast (*ptr.getRefData().getCustomData()).mMovement; + } + + Ogre::Vector3 Creature::getMovementVector (const MWWorld::Ptr& ptr) const + { + MWMechanics::Movement &movement = getMovementSettings(ptr); + Ogre::Vector3 vec(movement.mPosition); + movement.mPosition[0] = 0.0f; + movement.mPosition[1] = 0.0f; + movement.mPosition[2] = 0.0f; + return vec; + } + + Ogre::Vector3 Creature::getRotationVector (const MWWorld::Ptr& ptr) const + { + MWMechanics::Movement &movement = getMovementSettings(ptr); + Ogre::Vector3 vec(movement.mRotation); + movement.mRotation[0] = 0.0f; + movement.mRotation[1] = 0.0f; + movement.mRotation[2] = 0.0f; + return vec; + } + MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -249,4 +299,7 @@ namespace MWClass return MWWorld::Ptr(&cell.mCreatures.insert(*ref), &cell); } + + const ESM::GameSetting* Creature::fMinWalkSpeedCreature; + const ESM::GameSetting* Creature::fMaxWalkSpeedCreature; } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index b5657e265..5c30004cd 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -12,6 +12,9 @@ namespace MWClass virtual MWWorld::Ptr copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + static const ESM::GameSetting *fMinWalkSpeedCreature; + static const ESM::GameSetting *fMaxWalkSpeedCreature; + public: virtual std::string getId (const MWWorld::Ptr& ptr) const; @@ -66,6 +69,18 @@ namespace MWClass virtual bool isPersistent (const MWWorld::Ptr& ptr) const; + virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; + ///< Return desired movement. + + virtual Ogre::Vector3 getMovementVector (const MWWorld::Ptr& ptr) const; + ///< Return desired movement vector (determined based on movement settings, + /// stance and stats). + + virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + + float getSpeed (const MWWorld::Ptr& ptr) const; + static void registerSelf(); virtual std::string getModel(const MWWorld::Ptr &ptr) const; diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index ef688be1b..94f834a4d 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -223,6 +223,9 @@ struct TypesetBookImpl::Typesetter : BookTypesetter Style * createStyle (char const * fontName, Colour fontColour) { + if (strcmp(fontName, "") == 0) + return createStyle(MyGUI::FontManager::getInstance().getDefaultFont().c_str(), fontColour); + for (Styles::iterator i = mBook->mStyles.begin (); i != mBook->mStyles.end (); ++i) if (i->match (fontName, fontColour, fontColour, fontColour, 0)) return &*i; @@ -405,7 +408,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter while (!stream.eof () && !ucsLineBreak (stream.peek ()) && ucsBreakingSpace (stream.peek ())) { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); - space_width += gi->advance; + if (gi) + space_width += gi->advance + gi->bearingX; stream.consume (); } @@ -414,7 +418,8 @@ struct TypesetBookImpl::Typesetter : BookTypesetter while (!stream.eof () && !ucsLineBreak (stream.peek ()) && !ucsBreakingSpace (stream.peek ())) { MyGUI::GlyphInfo* gi = style->mFont->getGlyphInfo (stream.peek ()); - word_width += gi->advance + gi->bearingX; + if (gi) + word_width += gi->advance + gi->bearingX; word_height = line_height; ++character_count; stream.consume (); @@ -628,6 +633,9 @@ namespace { MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch); + if (!gi) + return; + MyGUI::FloatRect vr; vr.left = mCursor.left + gi->bearingX; @@ -647,7 +655,8 @@ namespace { MyGUI::GlyphInfo* gi = mFont->getGlyphInfo (ch); - mCursor.left += gi->bearingX + gi->advance; + if (gi) + mCursor.left += gi->bearingX + gi->advance; } private: diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 3b5deb5ac..f24922e23 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -130,26 +130,12 @@ namespace MWGui 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(); - } + nextPage(); } void BookWindow::onPrevPageButtonClicked (MyGUI::Widget* sender) { - if (mCurrentPage > 0) - { - MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); - - --mCurrentPage; - - updatePages(); - } + prevPage(); } void BookWindow::updatePages() @@ -194,5 +180,28 @@ namespace MWGui if (button->getAlign().isRight()) button->setPosition(button->getPosition() + MyGUI::IntPoint(diff.width,0)); } + + void BookWindow::nextPage() + { + if ((mCurrentPage+1)*2 < mPages.size()) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page2", 1.0, 1.0); + + ++mCurrentPage; + + updatePages(); + } + } + void BookWindow::prevPage() + { + if (mCurrentPage > 0) + { + MWBase::Environment::get().getSoundManager()->playSound ("book page", 1.0, 1.0); + + --mCurrentPage; + + updatePages(); + } + } } diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index c6ea486d4..ef87dd9c4 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -16,7 +16,8 @@ namespace MWGui void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); - + void nextPage(); + void prevPage(); void setInventoryAllowed(bool allowed); protected: diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index fc8c24484..6a6c596be 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -238,6 +238,12 @@ namespace MWGui } } + void CharacterCreation::doRenderUpdate() + { + if (mRaceDialog) + mRaceDialog->doRenderUpdate(); + } + void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) { mPlayerHealth = value; diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 586faf966..bd8826677 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -41,6 +41,7 @@ namespace MWGui void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); void configureSkills (const SkillList& major, const SkillList& minor); + void doRenderUpdate(); private: //Dialogs diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index ab8103868..2f00918b0 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -407,7 +407,7 @@ namespace MWGui getWidget(mEditName, "EditName"); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mEditName); MyGUI::Button* descriptionButton; getWidget(descriptionButton, "DescriptionButton"); @@ -866,7 +866,7 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } DescriptionDialog::~DescriptionDialog() diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index cba3412e9..f438d5e09 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -5,6 +5,7 @@ #include "../mwscript/extensions.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" namespace MWGui { @@ -131,16 +132,12 @@ namespace MWGui // Give keyboard focus to the combo box whenever the console is // turned on - MyGUI::InputManager::getInstance().setKeyFocusWidget(command); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(command); } void Console::disable() { setVisible(false); - setSelectedObject(MWWorld::Ptr()); - // Remove keyboard focus from the console input whenever the - // console is turned off - MyGUI::InputManager::getInstance().setKeyFocusWidget(NULL); } void Console::setFont(const std::string &fntName) @@ -415,7 +412,7 @@ namespace MWGui setTitle("#{sConsoleTitle}"); mPtr = MWWorld::Ptr(); } - MyGUI::InputManager::getInstance().setKeyFocusWidget(command); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(command); } void Console::onReferenceUnavailable() diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index 79351c6ca..5d23744b2 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -3,11 +3,39 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +namespace +{ + + bool stacks (const MWWorld::Ptr& left, const MWWorld::Ptr& right) + { + if (left == right) + return true; + + // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure + if (left.getContainerStore() && right.getContainerStore()) + return left.getContainerStore()->stacks(left, right) + && right.getContainerStore()->stacks(left, right); + + if (left.getContainerStore()) + return left.getContainerStore()->stacks(left, right); + if (right.getContainerStore()) + return right.getContainerStore()->stacks(left, right); + + MWWorld::ContainerStore store; + return store.stacks(left, right); + } + +} + namespace MWGui { -ContainerItemModel::ContainerItemModel(const std::vector& itemSources) +ContainerItemModel::ContainerItemModel(const std::vector& itemSources, const std::vector& worldItems) : mItemSources(itemSources) + , mWorldItems(worldItems) { assert (mItemSources.size()); } @@ -65,8 +93,7 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { - // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure - if (*it == item.mBase || (store.stacks(*it, item.mBase) && item.mBase.getContainerStore()->stacks(*it, item.mBase))) + if (stacks(*it, item.mBase)) { int refCount = it->getRefData().getCount(); it->getRefData().setCount(std::max(0, refCount - toRemove)); @@ -76,6 +103,21 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) } } } + for (std::vector::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source) + { + if (stacks(*source, item.mBase)) + { + int refCount = source->getRefData().getCount(); + if (refCount - toRemove <= 0) + MWBase::Environment::get().getWorld()->deleteObject(*source); + else + source->getRefData().setCount(std::max(0, refCount - toRemove)); + toRemove -= refCount; + if (toRemove <= 0) + return; + } + } + throw std::runtime_error("Not enough items to remove could be found"); } @@ -91,8 +133,7 @@ void ContainerItemModel::update() std::vector::iterator itemStack = mItems.begin(); for (; itemStack != mItems.end(); ++itemStack) { - // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure - if (store.stacks(itemStack->mBase, *it) && it->getContainerStore()->stacks(itemStack->mBase, *it)) + if (stacks(*it, itemStack->mBase)) { // we already have an item stack of this kind, add to it itemStack->mCount += it->getRefData().getCount(); @@ -108,6 +149,26 @@ void ContainerItemModel::update() } } } + for (std::vector::iterator source = mWorldItems.begin(); source != mWorldItems.end(); ++source) + { + std::vector::iterator itemStack = mItems.begin(); + for (; itemStack != mItems.end(); ++itemStack) + { + if (stacks(*source, itemStack->mBase)) + { + // we already have an item stack of this kind, add to it + itemStack->mCount += source->getRefData().getCount(); + break; + } + } + + if (itemStack == mItems.end()) + { + // no stack yet, create one + ItemStack newItem (*source, this, source->getRefData().getCount()); + mItems.push_back(newItem); + } + } } } diff --git a/apps/openmw/mwgui/containeritemmodel.hpp b/apps/openmw/mwgui/containeritemmodel.hpp index 2f4c708ba..22595582e 100644 --- a/apps/openmw/mwgui/containeritemmodel.hpp +++ b/apps/openmw/mwgui/containeritemmodel.hpp @@ -11,7 +11,7 @@ namespace MWGui class ContainerItemModel : public ItemModel { public: - ContainerItemModel (const std::vector& itemSources); + ContainerItemModel (const std::vector& itemSources, const std::vector& worldItems); ///< @note The order of elements \a itemSources matters here. The first element has the highest priority for removal, /// while the last element will be used to add new items to. @@ -28,6 +28,7 @@ namespace MWGui private: std::vector mItemSources; + std::vector mWorldItems; std::vector mItems; }; diff --git a/apps/openmw/mwgui/controllers.cpp b/apps/openmw/mwgui/controllers.cpp new file mode 100644 index 000000000..e62fb3fce --- /dev/null +++ b/apps/openmw/mwgui/controllers.cpp @@ -0,0 +1,54 @@ +#include "controllers.hpp" + +namespace MWGui +{ + namespace Controllers + { + + ControllerRepeatClick::ControllerRepeatClick() : + mInit(0.5), + mStep(0.1), + mEnabled(true), + mTimeLeft(0) + { + } + + ControllerRepeatClick::~ControllerRepeatClick() + { + } + + bool ControllerRepeatClick::addTime(MyGUI::Widget* _widget, float _time) + { + if(mTimeLeft == 0) + mTimeLeft = mInit; + + mTimeLeft -= _time; + while (mTimeLeft <= 0) + { + mTimeLeft += mStep; + eventRepeatClick(_widget, this); + } + return true; + } + + void ControllerRepeatClick::setRepeat(float init, float step) + { + mInit = init; + mStep = step; + } + + void ControllerRepeatClick::setEnabled(bool enable) + { + mEnabled = enable; + } + + void ControllerRepeatClick::setProperty(const std::string& _key, const std::string& _value) + { + } + + void ControllerRepeatClick::prepareItem(MyGUI::Widget* _widget) + { + } + + } +} diff --git a/apps/openmw/mwgui/controllers.hpp b/apps/openmw/mwgui/controllers.hpp new file mode 100644 index 000000000..798acde62 --- /dev/null +++ b/apps/openmw/mwgui/controllers.hpp @@ -0,0 +1,46 @@ +#ifndef MWGUI_CONTROLLERS_H +#define MWGUI_CONTROLLERS_H + +#include +#include + + +namespace MWGui +{ + namespace Controllers + { + class ControllerRepeatClick : + public MyGUI::ControllerItem + { + MYGUI_RTTI_DERIVED( ControllerRepeatClick ) + + public: + ControllerRepeatClick(); + virtual ~ControllerRepeatClick(); + + void setRepeat(float init, float step); + void setEnabled(bool enable); + virtual void setProperty(const std::string& _key, const std::string& _value); + + // Events + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_RepeatClickVoid; + + /** Event : Repeat Click.\n + signature : void method(MyGUI::Widget* _sender, MyGUI::ControllerItem *_controller)\n + */ + EventHandle_RepeatClickVoid eventRepeatClick; + + private: + bool addTime(MyGUI::Widget* _widget, float _time); + void prepareItem(MyGUI::Widget* _widget); + + private: + float mInit; + float mStep; + bool mEnabled; + float mTimeLeft; + }; + } +} + +#endif diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 354de561d..c429b0ccf 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -2,6 +2,9 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { CountDialog::CountDialog() : @@ -40,7 +43,7 @@ namespace MWGui mMainWidget->getHeight()); // by default, the text edit field has the focus of the keyboard - MyGUI::InputManager::getInstance().setKeyFocusWidget(mItemEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mItemEdit); mSlider->setScrollPosition(maxCount-1); mItemEdit->setCaption(boost::lexical_cast(maxCount)); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 2eacd973e..c9a780691 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -7,6 +7,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwmechanics/npcstats.hpp" @@ -115,7 +116,7 @@ namespace MWGui void Response::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f)); + BookTypesetter::Style* title = typesetter->createStyle("", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f)); typesetter->sectionBreak(9); if (mTitle != "") typesetter->write(title, to_utf8_span(mTitle.c_str())); @@ -159,7 +160,7 @@ namespace MWGui if (hyperLinks.size() && MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) { - BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f)); + BookTypesetter::Style* style = typesetter->createStyle("", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f)); size_t formatted = 0; // points to the first character that is not laid out yet for (std::map::iterator it = hyperLinks.begin(); it != hyperLinks.end(); ++it) { @@ -197,7 +198,7 @@ namespace MWGui void Response::addTopicLink(BookTypesetter::Ptr typesetter, intptr_t topicId, size_t begin, size_t end) const { - BookTypesetter::Style* style = typesetter->createStyle("EB Garamond", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f)); + BookTypesetter::Style* style = typesetter->createStyle("", MyGUI::Colour(202/255.f, 165/255.f, 96/255.f)); const MyGUI::Colour linkHot (143/255.f, 155/255.f, 218/255.f); const MyGUI::Colour linkNormal (112/255.f, 126/255.f, 207/255.f); @@ -215,7 +216,7 @@ namespace MWGui void Message::write(BookTypesetter::Ptr typesetter, KeywordSearchT* keywordSearch, std::map& topicLinks) const { - BookTypesetter::Style* title = typesetter->createStyle("EB Garamond", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f)); + BookTypesetter::Style* title = typesetter->createStyle("", MyGUI::Colour(223/255.f, 201/255.f, 159/255.f)); typesetter->sectionBreak(9); typesetter->write(title, to_utf8_span(mText.c_str())); } @@ -224,16 +225,22 @@ namespace MWGui void Choice::activated() { + + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.0, 1.0); MWBase::Environment::get().getDialogueManager()->questionAnswered(mChoiceId); } void Topic::activated() { + + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); MWBase::Environment::get().getDialogueManager()->keywordSelected(Misc::StringUtils::lowerCase(mTopicId)); } void Goodbye::activated() { + + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); } @@ -465,13 +472,14 @@ namespace MWGui (*it)->write(typesetter, &mKeywordSearch, mTopicLinks); - BookTypesetter::Style* body = typesetter->createStyle("EB Garamond", MyGUI::Colour::White); + BookTypesetter::Style* body = typesetter->createStyle("", MyGUI::Colour::White); + typesetter->sectionBreak(9); // choices const MyGUI::Colour linkHot (223/255.f, 201/255.f, 159/255.f); const MyGUI::Colour linkNormal (150/255.f, 50/255.f, 30/255.f); const MyGUI::Colour linkActive (243/255.f, 237/255.f, 221/255.f); - for (std::map::iterator it = mChoices.begin(); it != mChoices.end(); ++it) + for (std::map::reverse_iterator it = mChoices.rbegin(); it != mChoices.rend(); ++it) { Choice* link = new Choice(it->second); mLinks.push_back(link); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 799a89ab5..98ba8ec2f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -61,30 +61,32 @@ namespace MWGui void EnchantingDialog::updateLabels() { std::stringstream enchantCost; - enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantCost(); + enchantCost << std::setprecision(1) << std::fixed << mEnchanting.getEnchantPoints(); mEnchantmentPoints->setCaption(enchantCost.str() + " / " + boost::lexical_cast(mEnchanting.getMaxEnchantValue())); mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); - mCastCost->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost())); + std::stringstream castCost; + castCost << std::setprecision(1) << std::fixed << mEnchanting.getCastCost(); + mCastCost->setCaption(boost::lexical_cast(castCost.str())); mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); - switch(mEnchanting.getEnchantType()) + switch(mEnchanting.getCastStyle()) { - case 0: + case ESM::Enchantment::CastOnce: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); mAddEffectDialog.constantEffect=false; break; - case 1: + case ESM::Enchantment::WhenStrikes: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); mAddEffectDialog.constantEffect=false; break; - case 2: + case ESM::Enchantment::WhenUsed: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); mAddEffectDialog.constantEffect=false; break; - case 3: + case ESM::Enchantment::ConstantEffect: mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); mAddEffectDialog.constantEffect=true; break; @@ -169,7 +171,7 @@ namespace MWGui image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem); mEnchanting.setOldItem(item); - mEnchanting.nextEnchantType(); + mEnchanting.nextCastStyle(); updateLabels(); } @@ -248,7 +250,7 @@ namespace MWGui void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender) { - mEnchanting.nextEnchantType(); + mEnchanting.nextCastStyle(); updateLabels(); } @@ -278,7 +280,7 @@ namespace MWGui return; } - if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue()) + if (mEnchanting.getEnchantPoints() > mEnchanting.getMaxEnchantValue()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}"); return; diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp new file mode 100644 index 000000000..ff160105a --- /dev/null +++ b/apps/openmw/mwgui/fontloader.cpp @@ -0,0 +1,238 @@ +#include "fontloader.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace +{ + unsigned long utf8ToUnicode(const std::string& utf8) + { + size_t i = 0; + unsigned long unicode; + size_t todo; + unsigned char ch = utf8[i++]; + if (ch <= 0x7F) + { + unicode = ch; + todo = 0; + } + else if (ch <= 0xBF) + { + throw std::logic_error("not a UTF-8 string"); + } + else if (ch <= 0xDF) + { + unicode = ch&0x1F; + todo = 1; + } + else if (ch <= 0xEF) + { + unicode = ch&0x0F; + todo = 2; + } + else if (ch <= 0xF7) + { + unicode = ch&0x07; + todo = 3; + } + else + { + throw std::logic_error("not a UTF-8 string"); + } + for (size_t j = 0; j < todo; ++j) + { + unsigned char ch = utf8[i++]; + if (ch < 0x80 || ch > 0xBF) + throw std::logic_error("not a UTF-8 string"); + unicode <<= 6; + unicode += ch & 0x3F; + } + if (unicode >= 0xD800 && unicode <= 0xDFFF) + throw std::logic_error("not a UTF-8 string"); + if (unicode > 0x10FFFF) + throw std::logic_error("not a UTF-8 string"); + + return unicode; + } +} + +namespace MWGui +{ + + FontLoader::FontLoader(ToUTF8::FromType encoding) + { + if (encoding == ToUTF8::WINDOWS_1252) + mEncoding = ToUTF8::CP437; + else + mEncoding = encoding; + } + + void FontLoader::loadAllFonts() + { + 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, "*.fnt"); + for (Ogre::StringVector::iterator resource = resourcesInThisGroup->begin(); resource != resourcesInThisGroup->end(); ++resource) + { + loadFont(*resource); + } + } + } + + + typedef struct + { + float x; + float y; + } Point; + + typedef struct + { + float u1; // appears unused, always 0 + Point top_left; + Point top_right; + Point bottom_left; + Point bottom_right; + float width; + float height; + float u2; // appears unused, always 0 + float kerning; + float ascent; + } GlyphInfo; + + void FontLoader::loadFont(const std::string &fileName) + { + Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName); + + float fontSize; + int one; + file->read(&fontSize, sizeof(fontSize)); + + file->read(&one, sizeof(int)); + assert(one == 1); + file->read(&one, sizeof(int)); + assert(one == 1); + + char name_[284]; + file->read(name_, sizeof(name_)); + std::string name(name_); + + GlyphInfo data[256]; + file->read(data, sizeof(data)); + file->close(); + + // Create the font texture + std::string bitmapFilename = "Fonts/" + std::string(name) + ".tex"; + Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename); + + int width, height; + bitmapFile->read(&width, sizeof(int)); + bitmapFile->read(&height, sizeof(int)); + + std::vector textureData; + textureData.resize(width*height*4); + bitmapFile->read(&textureData[0], width*height*4); + bitmapFile->close(); + + std::string textureName = name; + Ogre::Image image; + image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA); + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName, + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + width, height, 0, Ogre::PF_BYTE_RGBA); + texture->loadImage(image); + + // Register the font with MyGUI + MyGUI::ResourceManualFont* font = static_cast( + MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont")); + // We need to emulate loading from XML because the data members are private as of mygui 3.2.0 + MyGUI::xml::Document xmlDocument; + MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont"); + + if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic")) + root->addAttribute("name", "Magic Cards"); + else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century")) + root->addAttribute("name", "Century Gothic"); + else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric")) + root->addAttribute("name", "Daedric"); + else + return; // no point in loading it, since there is no way of using additional fonts + + MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property"); + defaultHeight->addAttribute("key", "DefaultHeight"); + defaultHeight->addAttribute("value", fontSize); + MyGUI::xml::ElementPtr source = root->createChild("Property"); + source->addAttribute("key", "Source"); + source->addAttribute("value", std::string(textureName)); + MyGUI::xml::ElementPtr codes = root->createChild("Codes"); + + for(int i = 0; i < 256; i++) + { + int x1 = data[i].top_left.x*width; + int y1 = data[i].top_left.y*height; + int w = data[i].top_right.x*width - x1; + int h = data[i].bottom_left.y*height - y1; + + ToUTF8::Utf8Encoder encoder(mEncoding); + unsigned long unicodeVal = utf8ToUnicode(encoder.getUtf8(std::string(1, (unsigned char)(i)))); + + MyGUI::xml::ElementPtr code = codes->createChild("Code"); + code->addAttribute("index", unicodeVal); + code->addAttribute("coord", MyGUI::utility::toString(x1) + " " + + MyGUI::utility::toString(y1) + " " + + MyGUI::utility::toString(w) + " " + + MyGUI::utility::toString(h)); + code->addAttribute("advance", data[i].width); + code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + + MyGUI::utility::toString((fontSize-data[i].ascent))); + + // ASCII vertical bar, use this as text input cursor + if (i == 124) + { + MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code"); + cursorCode->addAttribute("index", MyGUI::FontCodeType::Cursor); + cursorCode->addAttribute("coord", MyGUI::utility::toString(x1) + " " + + MyGUI::utility::toString(y1) + " " + + MyGUI::utility::toString(w) + " " + + MyGUI::utility::toString(h)); + cursorCode->addAttribute("advance", data[i].width); + cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " " + + MyGUI::utility::toString((fontSize-data[i].ascent))); + } + } + + // These are required as well, but the fonts don't provide them + for (int i=0; i<3; ++i) + { + MyGUI::FontCodeType::Enum type; + if(i == 0) + type = MyGUI::FontCodeType::Selected; + else if (i == 1) + type = MyGUI::FontCodeType::SelectedBack; + else if (i == 2) + type = MyGUI::FontCodeType::NotDefined; + + MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code"); + cursorCode->addAttribute("index", type); + cursorCode->addAttribute("coord", "0 0 0 0"); + cursorCode->addAttribute("advance", "0"); + cursorCode->addAttribute("bearing", "0 0"); + + } + + font->deserialization(root, MyGUI::Version(3,2,0)); + + MyGUI::ResourceManager::getInstance().addResource(font); + } + +} diff --git a/apps/openmw/mwgui/fontloader.hpp b/apps/openmw/mwgui/fontloader.hpp new file mode 100644 index 000000000..7954b0875 --- /dev/null +++ b/apps/openmw/mwgui/fontloader.hpp @@ -0,0 +1,25 @@ +#ifndef MWGUI_FONTLOADER_H +#define MWGUI_FONTLOADER_H + +#include + +namespace MWGui +{ + + + /// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and Ogre + class FontLoader + { + public: + FontLoader (ToUTF8::FromType encoding); + void loadAllFonts (); + + private: + ToUTF8::FromType mEncoding; + + void loadFont (const std::string& fileName); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index aebaf16a2..58d963ce8 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -202,14 +202,14 @@ namespace MWGui float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const { - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : 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); + std::string fontName(mTextStyle.mFont == "Default" ? MyGUI::FontManager::getInstance().getDefaultFont() : mTextStyle.mFont); return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); } @@ -251,10 +251,8 @@ namespace MWGui MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); } - boost::algorithm::replace_all(text, "\n", "\n"); - boost::algorithm::replace_all(text, "\r", "\r"); - boost::algorithm::replace_all(text, "
", "\n\n"); - boost::algorithm::replace_all(text, "

", "\n\n"); // tweaking by adding another newline to see if that spaces out better + boost::algorithm::replace_all(text, "
", "\n"); + boost::algorithm::replace_all(text, "

", "\n\n"); boost::algorithm::trim_left(text); // remove trailing " diff --git a/apps/openmw/mwgui/itemmodel.cpp b/apps/openmw/mwgui/itemmodel.cpp index 0dc2bb62c..58e89c4fc 100644 --- a/apps/openmw/mwgui/itemmodel.cpp +++ b/apps/openmw/mwgui/itemmodel.cpp @@ -13,8 +13,6 @@ namespace MWGui , mType(Type_Normal) , mBase(base) { - assert(base.getContainerStore()); - if (MWWorld::Class::get(base).getEnchantment(base) != "") mFlags |= Flag_Enchanted; } @@ -31,18 +29,42 @@ namespace MWGui { if(mBase == other.mBase) return true; - return mBase.getContainerStore()->stacks(mBase, other.mBase) - && other.mBase.getContainerStore()->stacks(mBase, other.mBase); + + // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure + if (mBase.getContainerStore() && other.mBase.getContainerStore()) + return mBase.getContainerStore()->stacks(mBase, other.mBase) + && other.mBase.getContainerStore()->stacks(mBase, other.mBase); + + if (mBase.getContainerStore()) + return mBase.getContainerStore()->stacks(mBase, other.mBase); + if (other.mBase.getContainerStore()) + return other.mBase.getContainerStore()->stacks(mBase, other.mBase); + + MWWorld::ContainerStore store; + return store.stacks(mBase, other.mBase); + } bool operator == (const ItemStack& left, const ItemStack& right) { if (left.mType != right.mType) return false; + if(left.mBase == right.mBase) return true; - return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase) - && right.mBase.getContainerStore()->stacks(left.mBase, right.mBase); + + // If one of the items is in an inventory and currently equipped, we need to check stacking both ways to be sure + if (left.mBase.getContainerStore() && right.mBase.getContainerStore()) + return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase) + && right.mBase.getContainerStore()->stacks(left.mBase, right.mBase); + + if (left.mBase.getContainerStore()) + return left.mBase.getContainerStore()->stacks(left.mBase, right.mBase); + if (right.mBase.getContainerStore()) + return right.mBase.getContainerStore()->stacks(left.mBase, right.mBase); + + MWWorld::ContainerStore store; + return store.stacks(left.mBase, right.mBase); } ItemModel::ItemModel() diff --git a/apps/openmw/mwgui/journalbooks.cpp b/apps/openmw/mwgui/journalbooks.cpp index 273985e3e..dbea10e77 100644 --- a/apps/openmw/mwgui/journalbooks.cpp +++ b/apps/openmw/mwgui/journalbooks.cpp @@ -189,14 +189,14 @@ book JournalBooks::createEmptyJournalBook () { BookTypesetter::Ptr typesetter = createTypesetter (); - BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f)); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); typesetter->write (header, to_utf8_span ("You have no journal entries!")); typesetter->lineBreak (); typesetter->write (body, to_utf8_span ("You should have gone though the starting quest and got an initial quest.")); - BookTypesetter::Style* big = typesetter->createStyle ("EB Garamond 24", MyGUI::Colour::Black); + BookTypesetter::Style* big = typesetter->createStyle ("", MyGUI::Colour::Black); BookTypesetter::Style* test = typesetter->createStyle ("MonoFont", MyGUI::Colour::Blue); typesetter->sectionBreak (20); @@ -231,8 +231,8 @@ book JournalBooks::createJournalBook () { BookTypesetter::Ptr typesetter = createTypesetter (); - BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f)); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitJournalEntries (0, AddJournalEntry (typesetter, body, header, true)); @@ -243,8 +243,8 @@ book JournalBooks::createTopicBook (uintptr_t topicId) { BookTypesetter::Ptr typesetter = createTypesetter (); - BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f)); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitTopicName (topicId, AddTopicName (typesetter, header)); @@ -259,8 +259,8 @@ book JournalBooks::createQuestBook (uintptr_t questId) { BookTypesetter::Ptr typesetter = createTypesetter (); - BookTypesetter::Style* header = typesetter->createStyle ("EB Garamond", MyGUI::Colour (0.60f, 0.00f, 0.00f)); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* header = typesetter->createStyle ("", MyGUI::Colour (0.60f, 0.00f, 0.00f)); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitQuestName (questId, AddQuestName (typesetter, header)); @@ -275,7 +275,7 @@ book JournalBooks::createTopicIndexBook () typesetter->setSectionAlignment (BookTypesetter::AlignCenter); - BookTypesetter::Style* body = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); for (int i = 0; i < 26; ++i) { @@ -300,7 +300,7 @@ book JournalBooks::createTopicIndexBook () book JournalBooks::createTopicIndexBook (char character) { BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF); - BookTypesetter::Style* style = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* style = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitTopicNamesStartingWith (character, AddTopicLink (typesetter, style)); @@ -310,7 +310,7 @@ book JournalBooks::createTopicIndexBook (char character) book JournalBooks::createQuestIndexBook (bool activeOnly) { BookTypesetter::Ptr typesetter = BookTypesetter::create (0x7FFFFFFF, 0x7FFFFFFF); - BookTypesetter::Style* base = typesetter->createStyle ("EB Garamond", MyGUI::Colour::Black); + BookTypesetter::Style* base = typesetter->createStyle ("", MyGUI::Colour::Black); mModel->visitQuestNames (activeOnly, AddQuestLink (typesetter, base)); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 5b84c99a5..ab8dc1584 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -183,7 +183,7 @@ namespace if (!MWBase::Environment::get().getWindowManager ()->getJournalAllowed ()) { MWBase::Environment::get().getWindowManager()->popGuiMode (); - } + } mModel->load (); setBookMode (); @@ -433,7 +433,6 @@ namespace void notifyClose(MyGUI::Widget* _sender) { MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); - MWBase::Environment::get().getWindowManager ()->popGuiMode (); } diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 018f51feb..d4b06b2ab 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -10,6 +10,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/inputmanager.hpp" namespace MWGui { @@ -126,7 +127,7 @@ namespace MWGui // always update input before rendering something, otherwise mygui goes crazy when something was entered in the frame before // (e.g. when using "coc" console command, it would enter an infinite loop and crash due to overflow) - //MWBase::Environment::get().getInputManager()->update(0, true); + MWBase::Environment::get().getInputManager()->update(0, true); Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0)); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 4a78238ce..7098853af 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -34,6 +34,10 @@ namespace MWGui { } + LocalMapBase::~LocalMapBase() + { + } + void LocalMapBase::init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop) { mLocalMap = widget; diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 18c81a060..3aefc398c 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -14,6 +14,7 @@ namespace MWGui { public: LocalMapBase(); + virtual ~LocalMapBase(); void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, OEngine::GUI::Layout* layout, bool mapDragAndDrop=false); void setCellPrefix(const std::string& prefix); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9065333f5..ba06c8d10 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -32,6 +32,7 @@ namespace MWGui , mFaceIndex(0) , mHairIndex(0) , mCurrentAngle(0) + , mPreviewDirty(true) { // Centre dialog center(); @@ -126,6 +127,8 @@ namespace MWGui mHairIndex = boost::lexical_cast(index) - 1; mPreviewImage->setImageTexture ("CharacterHeadPreview"); + + mPreviewDirty = true; } @@ -174,6 +177,7 @@ namespace MWGui float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2; float diff = angle - mCurrentAngle; mPreview->update (diff); + mPreviewDirty = true; mCurrentAngle += diff; } @@ -286,6 +290,16 @@ namespace MWGui record.mHair = mAvailableHairs[mHairIndex]; mPreview->setPrototype(record); + mPreviewDirty = true; + } + + void RaceDialog::doRenderUpdate() + { + if (mPreviewDirty) + { + mPreview->render(); + mPreviewDirty = false; + } } void RaceDialog::updateRaces() diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 1d48c67cd..914ae8096 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -52,6 +52,8 @@ namespace MWGui */ EventHandle_Void eventBack; + void doRenderUpdate(); + protected: void onHeadRotate(MyGUI::ScrollBar* _sender, size_t _position); @@ -98,6 +100,8 @@ namespace MWGui float mCurrentAngle; MWRender::RaceSelectionPreview* mPreview; + + bool mPreviewDirty; }; } #endif diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 413171dd4..97bccd01f 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -126,7 +126,6 @@ namespace MWGui getWidget(mControlsBox, "ControlsBox"); getWidget(mResetControlsButton, "ResetControlsButton"); getWidget(mInvertYButton, "InvertYButton"); - getWidget(mUISensitivitySlider, "UISensitivitySlider"); getWidget(mCameraSensitivitySlider, "CameraSensitivitySlider"); getWidget(mRefractionButton, "RefractionButton"); @@ -240,11 +239,7 @@ namespace MWGui float cameraSens = (Settings::Manager::getFloat("camera sensitivity", "Input")-0.2)/(5.0-0.2); mCameraSensitivitySlider->setScrollPosition (cameraSens * (mCameraSensitivitySlider->getScrollRange()-1)); - float uiSens = (Settings::Manager::getFloat("ui sensitivity", "Input")-0.2)/(5.0-0.2); - mUISensitivitySlider->setScrollPosition (uiSens * (mUISensitivitySlider->getScrollRange()-1)); mCameraSensitivitySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mUISensitivitySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); - mInvertYButton->setCaptionWithReplacing(Settings::Manager::getBool("invert y axis", "Input") ? "#{sOn}" : "#{sOff}"); @@ -274,12 +269,15 @@ namespace MWGui if (index == MyGUI::ITEM_NONE) return; + /* ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sNotifyMessage67}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); dialog->eventCancelClicked.clear(); dialog->eventCancelClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionCancel); + */ + onResolutionAccept(); } void SettingsWindow::onResolutionAccept() @@ -292,7 +290,9 @@ namespace MWGui Settings::Manager::setInt("resolution y", "Video", resY); apply(); - mResolutionList->setIndexSelected(MyGUI::ITEM_NONE); + + MWBase::Environment::get().getWindowManager()-> + messageBox("New resolution will be applied after a restart", std::vector()); } void SettingsWindow::onResolutionCancel() @@ -361,6 +361,8 @@ namespace MWGui { Settings::Manager::setBool("fullscreen", "Video", newState); apply(); + MWBase::Environment::get().getWindowManager()-> + messageBox("Fullscreen will be applied after a restart", std::vector()); } } else if (_sender == mVSyncButton) @@ -529,8 +531,6 @@ namespace MWGui Settings::Manager::setFloat("footsteps volume", "Sound", val); else if (scroller == mMusicVolumeSlider) Settings::Manager::setFloat("music volume", "Sound", val); - else if (scroller == mUISensitivitySlider) - Settings::Manager::setFloat("ui sensitivity", "Input", (1-val) * 0.2 + val * 5.f); else if (scroller == mCameraSensitivitySlider) Settings::Manager::setFloat("camera sensitivity", "Input", (1-val) * 0.2 + val * 5.f); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 6dcef2422..20e9907d9 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -71,7 +71,6 @@ namespace MWGui MyGUI::ScrollView* mControlsBox; MyGUI::Button* mResetControlsButton; MyGUI::Button* mInvertYButton; - MyGUI::ScrollBar* mUISensitivitySlider; MyGUI::ScrollBar* mCameraSensitivitySlider; void onOkButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 60cc2fb0e..3cf514dc5 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -71,7 +71,7 @@ namespace MWGui if (item.mType == ItemStack::Type_Equipped && !mShowEquipped) return false; - int category; + int category = 0; if (base.getTypeName() == typeid(ESM::Armor).name() || base.getTypeName() == typeid(ESM::Clothing).name()) category = Category_Apparel; @@ -106,6 +106,7 @@ namespace MWGui if ((mFilter & Filter_OnlyEnchantable) && (item.mFlags & ItemStack::Flag_Enchanted || (base.getTypeName() != typeid(ESM::Armor).name() && base.getTypeName() != typeid(ESM::Clothing).name() + && base.getTypeName() != typeid(ESM::Weapon).name() && base.getTypeName() != typeid(ESM::Book).name()))) return false; if ((mFilter & Filter_OnlyEnchantable) && base.getTypeName() == typeid(ESM::Book).name() diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 45cf1b0aa..c4c1be711 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -416,6 +416,10 @@ namespace MWGui mAddEffectDialog.setVisible (false); } + EffectEditorBase::~EffectEditorBase() + { + } + void EffectEditorBase::startEditing () { // get the list of magic effects that are known to the player diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 5ad306fbe..61b888491 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -84,7 +84,7 @@ namespace MWGui { public: EffectEditorBase(); - + virtual ~EffectEditorBase(); protected: std::map mButtonMapping; // maps button ID to effect ID diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index d4f8a2533..954bc41ab 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -20,7 +20,7 @@ namespace MWGui okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } void TextInputDialog::setNextButtonShow(bool shown) @@ -43,7 +43,7 @@ namespace MWGui { WindowModal::open(); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } // widget controls @@ -53,7 +53,7 @@ namespace MWGui if (mTextEdit->getCaption() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); } else eventDone(this); @@ -64,7 +64,7 @@ namespace MWGui if (mTextEdit->getCaption() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); } else eventDone(this); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e73ed6b5e..9cbb3cced 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -18,7 +18,6 @@ namespace MWGui ToolTips::ToolTips() : Layout("openmw_tooltips.layout") - , mGameMode(true) , mFullHelp(false) , mEnabled(true) , mFocusToolTipX(0.0) @@ -73,7 +72,9 @@ namespace MWGui return; } - if (!mGameMode) + bool gameMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + + if (gameMode) { const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); @@ -297,16 +298,6 @@ namespace MWGui } } - void ToolTips::enterGameMode() - { - mGameMode = true; - } - - void ToolTips::enterGuiMode() - { - mGameMode = false; - } - void ToolTips::setFocusObject(const MWWorld::Ptr& focus) { mFocusObject = focus; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index f8f256167..a8524a4ca 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -43,9 +43,6 @@ namespace MWGui void onFrame(float frameDuration); - void enterGameMode(); - void enterGuiMode(); - void setEnabled(bool enabled); void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) @@ -104,8 +101,6 @@ namespace MWGui int mLastMouseX; int mLastMouseY; - bool mGameMode; - bool mEnabled; bool mFullHelp; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 6a46478af..01f7e2419 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -88,8 +88,10 @@ namespace MWGui MWBase::Environment::get().getWorld()->getContainersOwnedBy(actor, itemSources); // Important: actor goes last, so that items purchased by the merchant go into his inventory itemSources.push_back(actor); + std::vector worldItems; + MWBase::Environment::get().getWorld()->getItemsOwnedBy(actor, worldItems); - mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources), mPtr); + mTradeModel = new TradeItemModel(new ContainerItemModel(itemSources, worldItems), mPtr); mSortModel = new SortFilterItemModel(mTradeModel); mItemView->setModel (mSortModel); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index ad2b4710c..97c869b07 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -15,8 +15,6 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" -#include "widgets.hpp" - namespace MWGui { @@ -53,15 +51,14 @@ namespace MWGui getWidget(mDateTimeText, "DateTimeText"); getWidget(mRestText, "RestText"); getWidget(mHourText, "HourText"); - getWidget(mHourSlider, "HourSlider"); getWidget(mUntilHealedButton, "UntilHealedButton"); getWidget(mWaitButton, "WaitButton"); getWidget(mCancelButton, "CancelButton"); + getWidget(mHourSlider, "HourSlider"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onCancelButtonClicked); mUntilHealedButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onUntilHealedButtonClicked); mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); - mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); mProgressBar.setVisible (false); diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index d06d7d112..2723f7a80 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -2,6 +2,7 @@ #define MWGUI_WAIT_DIALOG_H #include "windowbase.hpp" +#include "widgets.hpp" namespace MWGui { @@ -38,10 +39,10 @@ namespace MWGui MyGUI::TextBox* mDateTimeText; MyGUI::TextBox* mRestText; MyGUI::TextBox* mHourText; - MyGUI::ScrollBar* mHourSlider; MyGUI::Button* mUntilHealedButton; MyGUI::Button* mWaitButton; MyGUI::Button* mCancelButton; + MWGui::Widgets::MWScrollBar* mHourSlider; bool mWaiting; bool mSleeping; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 1662c0597..04ef0e7cb 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -893,5 +894,113 @@ namespace MWGui { align(); } + + MWScrollBar::MWScrollBar() + : mEnableRepeat(true) + , mRepeatTriggerTime(0.5) + , mRepeatStepTime(0.1) + { + } + + MWScrollBar::~MWScrollBar() + { + } + + void MWScrollBar::initialiseOverride() + { + ScrollBar::initialiseOverride(); + + if(mWidgetStart) + { + mWidgetStart->eventMouseButtonPressed += MyGUI::newDelegate(this, &MWScrollBar::onDecreaseButtonPressed); + mWidgetStart->eventMouseButtonReleased += MyGUI::newDelegate(this, &MWScrollBar::onDecreaseButtonReleased); + } + if(mWidgetEnd) + { + mWidgetEnd->eventMouseButtonPressed += MyGUI::newDelegate(this, &MWScrollBar::onIncreaseButtonPressed); + mWidgetEnd->eventMouseButtonReleased += MyGUI::newDelegate(this, &MWScrollBar::onIncreaseButtonReleased); + } + } + + void MWScrollBar::setEnableRepeat(bool enable) + { + mEnableRepeat = enable; + } + + bool MWScrollBar::getEnableRepeat() + { + return mEnableRepeat; + } + + void MWScrollBar::getRepeat(float &trigger, float &step) + { + trigger = mRepeatTriggerTime; + step = mRepeatStepTime; + } + + void MWScrollBar::setRepeat(float trigger, float step) + { + mRepeatTriggerTime = trigger; + mRepeatStepTime = step; + } + + void MWScrollBar::repeatClick(MyGUI::Widget* _widget, MyGUI::ControllerItem* _controller) + { + int stepSize = mScrollPage; + + if(mIsIncreasing && mScrollPosition < mScrollRange-1) + { + if(mScrollPosition + stepSize > mScrollRange-1) + mScrollPosition = mScrollRange-1; + else + mScrollPosition += stepSize; + + eventScrollChangePosition(this, mScrollPosition); + updateTrack(); + } + else if(!mIsIncreasing && mScrollPosition > 0) + { + int newPos = mScrollPosition - stepSize; + if(newPos < 0) + mScrollPosition = 0; + else + mScrollPosition -= stepSize; + + eventScrollChangePosition(this, mScrollPosition); + updateTrack(); + } + } + + void MWScrollBar::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + mIsIncreasing = false; + MyGUI::ControllerItem* item = MyGUI::ControllerManager::getInstance().createItem(MWGui::Controllers::ControllerRepeatClick::getClassTypeName()); + MWGui::Controllers::ControllerRepeatClick* controller = item->castType(); + controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick); + controller->setEnabled(mEnableRepeat); + controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime); + MyGUI::ControllerManager::getInstance().addItem(this, controller); + } + + void MWScrollBar::onDecreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + MyGUI::ControllerManager::getInstance().removeItem(this); + } + + void MWScrollBar::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + mIsIncreasing = true; + MyGUI::ControllerItem* item = MyGUI::ControllerManager::getInstance().createItem(MWGui::Controllers::ControllerRepeatClick::getClassTypeName()); + MWGui::Controllers::ControllerRepeatClick* controller = item->castType(); + controller->eventRepeatClick += newDelegate(this, &MWScrollBar::repeatClick); + controller->setEnabled(mEnableRepeat); + controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime); + MyGUI::ControllerManager::getInstance().addItem(this, controller); + } + + void MWScrollBar::onIncreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + MyGUI::ControllerManager::getInstance().removeItem(this); + } } } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 156794691..1630ab3c9 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -3,9 +3,11 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/stat.hpp" +#include "controllers.hpp" #include #include +#include namespace MyGUI { @@ -407,6 +409,35 @@ namespace MWGui virtual void onWidgetCreated(MyGUI::Widget* _widget); }; + + class MWScrollBar : public MyGUI::ScrollBar + { + MYGUI_RTTI_DERIVED(MWScrollBar) + + public: + MWScrollBar(); + virtual ~MWScrollBar(); + + void setEnableRepeat(bool enable); + bool getEnableRepeat(); + void getRepeat(float &trigger, float &step); + void setRepeat(float trigger, float step); + + protected: + virtual void initialiseOverride(); + void repeatClick(MyGUI::Widget* _widget, MyGUI::ControllerItem* _controller); + + bool mEnableRepeat; + float mRepeatTriggerTime; + float mRepeatStepTime; + bool mIsIncreasing; + + private: + void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onDecreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onIncreaseButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + }; } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 48c5aba6b..0d40bc2be 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1,8 +1,18 @@ #include "windowmanagerimp.hpp" +#include +#include + +#include "MyGUI_UString.h" +#include "MyGUI_IPointer.h" +#include "MyGUI_ResourceImageSetPointer.h" +#include "MyGUI_TextureUtility.h" + #include #include +#include + #include "../mwbase/inputmanager.hpp" #include "../mwworld/class.hpp" @@ -42,6 +52,7 @@ #include "inventorywindow.hpp" #include "bookpage.hpp" #include "itemview.hpp" +#include "fontloader.hpp" namespace MWGui { @@ -49,7 +60,7 @@ namespace MWGui WindowManager::WindowManager( const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *ogre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage) + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding) : mGuiManager(NULL) , mRendering(ogre) , mHud(NULL) @@ -104,11 +115,17 @@ namespace MWGui , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHudEnabled(true) , mTranslationDataStorage (translationDataStorage) + , mCursorManager(NULL) + , mUseHardwareCursors(Settings::Manager::getBool("hardware cursors", "GUI")) { // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); mGui = mGuiManager->getGui(); + // Load fonts + FontLoader fontLoader (encoding); + fontLoader.loadAllFonts(); + //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); @@ -125,9 +142,12 @@ namespace MWGui MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::FactoryManager::getInstance().registerFactory("Widget"); BookPage::registerMyGUIComponents (); ItemView::registerComponents(); + MyGUI::FactoryManager::getInstance().registerFactory("Controller"); + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); @@ -183,7 +203,7 @@ namespace MWGui mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); - mCursor = new Cursor(); + mSoftwareCursor = new Cursor(); mHud->setVisible(mHudEnabled); @@ -203,6 +223,17 @@ namespace MWGui unsetSelectedSpell(); unsetSelectedWeapon(); + //set up the hardware cursor manager + mCursorManager = new SFO::SDLCursorManager(); + + MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); + + MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + + setUseHardwareCursors(mUseHardwareCursors); + onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); + mCursorManager->cursorVisibilityChange(false); + // Set up visibility updateVisible(); } @@ -257,7 +288,8 @@ namespace MWGui delete mMerchantRepair; delete mRepair; delete mSoulgemDialog; - delete mCursor; + delete mSoftwareCursor; + delete mCursorManager; cleanupGarbage(); @@ -287,7 +319,7 @@ namespace MWGui mHud->update(); - mCursor->update(); + mSoftwareCursor->update(); } void WindowManager::updateVisible() @@ -325,14 +357,10 @@ namespace MWGui bool gameMode = !isGuiMode(); mInputBlocker->setVisible (gameMode); + setCursorVisible(!gameMode); if (gameMode) - mToolTips->enterGameMode(); - else - mToolTips->enterGuiMode(); - - if (gameMode) - MyGUI::InputManager::getInstance ().setKeyFocusWidget (NULL); + setKeyFocusWidget (NULL); setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); @@ -457,7 +485,7 @@ namespace MWGui break; case GM_LoadingWallpaper: mHud->setVisible(false); - mCursor->setVisible(false); + setCursorVisible(false); break; case GM_Loading: // Show the pinned windows @@ -466,10 +494,10 @@ namespace MWGui mInventoryWindow->setVisible(mInventoryWindow->pinned()); mSpellWindow->setVisible(mSpellWindow->pinned()); - mCursor->setVisible(false); + setCursorVisible(false); break; case GM_Video: - mCursor->setVisible(false); + setCursorVisible(false); mHud->setVisible(false); break; default: @@ -795,17 +823,29 @@ namespace MWGui 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::setUseHardwareCursors(bool use) + { + mCursorManager->setEnabled(use); + mSoftwareCursor->setVisible(!use && mCursorVisible); + } + + void WindowManager::setCursorVisible(bool visible) + { + if(mCursorVisible == visible) + return; + + mCursorVisible = visible; + mCursorManager->cursorVisibilityChange(visible); + + mSoftwareCursor->setVisible(!mUseHardwareCursors && visible); + } + void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) { std::string tag(_tag); @@ -834,18 +874,20 @@ namespace MWGui mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); - bool changeRes = false; + setUseHardwareCursors(Settings::Manager::getBool("hardware cursors", "GUI")); + + //bool changeRes = false; bool windowRecreated = false; for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) { - if (it->first == "Video" && ( + /*if (it->first == "Video" && ( it->second == "resolution x" || it->second == "resolution y")) { changeRes = true; - } - else if (it->first == "Video" && it->second == "vsync") + }*/ + if (it->first == "Video" && it->second == "vsync") windowRecreated = true; else if (it->first == "HUD" && it->second == "crosshair") mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); @@ -853,6 +895,7 @@ namespace MWGui mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); } + /* if (changeRes) { int x = Settings::Manager::getInt("resolution x", "Video"); @@ -870,6 +913,7 @@ namespace MWGui mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); mInputBlocker->setSize(MyGUI::IntSize(x,y)); } + */ if (windowRecreated) { mGuiManager->updateWindow (mRendering->getWindow ()); @@ -897,6 +941,36 @@ namespace MWGui updateVisible(); } + void WindowManager::onCursorChange(const std::string &name) + { + mSoftwareCursor->onCursorChange(name); + + if(!mCursorManager->cursorChanged(name)) + return; //the cursor manager doesn't want any more info about this cursor + //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 cursor manager + 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; + int rotation = imgSetPtr->getRotation(); + + mCursorManager->receiveCursorInfo(name, rotation, tex, size_x, size_y, hotspot_x, hotspot_y); + } + } + } + void WindowManager::popGuiMode() { if (!mGuiModes.empty()) @@ -1104,6 +1178,14 @@ namespace MWGui allowMouse(); } + bool WindowManager::containsMode(GuiMode mode) const + { + if(mGuiModes.empty()) + return false; + + return std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end(); + } + void WindowManager::showCrosshair (bool show) { mHud->setCrosshairVisible (show && mCrosshairEnabled); @@ -1199,7 +1281,7 @@ namespace MWGui void WindowManager::changePointer(const std::string &name) { - mCursor->onCursorChange(name); + onCursorChange(name); } void WindowManager::showSoulgemDialog(MWWorld::Ptr item) @@ -1210,6 +1292,7 @@ namespace MWGui void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); + mCharGen->doRenderUpdate(); } void WindowManager::updatePlayer() @@ -1217,4 +1300,21 @@ namespace MWGui mInventoryWindow->updatePlayer(); } + void WindowManager::setKeyFocusWidget(MyGUI::Widget *widget) + { + if (widget == NULL) + MyGUI::InputManager::getInstance().resetKeyFocusWidget(); + else + MyGUI::InputManager::getInstance().setKeyFocusWidget(widget); + onKeyFocusChanged(widget); + } + + void WindowManager::onKeyFocusChanged(MyGUI::Widget *widget) + { + if (widget && widget->castType(false)) + SDL_StartTextInput(); + else + SDL_StopTextInput(); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 71bd2c9a7..42f2f4dc2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -43,6 +43,11 @@ namespace OEngine } } +namespace SFO +{ + class CursorManager; +} + namespace MWGui { class WindowBase; @@ -83,7 +88,7 @@ namespace MWGui WindowManager(const Compiler::Extensions& extensions, int fpsLevel, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage); + Translation::Storage& translationDataStorage, ToUTF8::FromType encoding); virtual ~WindowManager(); /** @@ -93,6 +98,8 @@ namespace MWGui */ virtual void update(); + virtual void setKeyFocusWidget (MyGUI::Widget* widget); + virtual void setNewGame(bool newgame); virtual void pushGuiMode(GuiMode mode); @@ -100,6 +107,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; @@ -153,7 +161,6 @@ 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 getMousePosition(int &x, int &y); virtual void getMousePosition(float &x, float &y); virtual void setDragDrop(bool dragDrop); @@ -289,7 +296,7 @@ namespace MWGui CompanionWindow* mCompanionWindow; Translation::Storage& mTranslationDataStorage; - Cursor* mCursor; + Cursor* mSoftwareCursor; CharacterCreation* mCharGen; @@ -298,6 +305,9 @@ namespace MWGui bool mCrosshairEnabled; bool mSubtitlesEnabled; bool mHudEnabled; + bool mCursorVisible; + + void setCursorVisible(bool visible); /// \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 @@ -312,6 +322,8 @@ namespace MWGui MyGUI::Gui *mGui; // Gui std::vector mGuiModes; + SFO::CursorManager* mCursorManager; + std::vector mGarbageDialogs; void cleanupGarbage(); @@ -333,11 +345,17 @@ namespace MWGui unsigned int mTriangleCount; unsigned int mBatchCount; + 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 */ void onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result); + + void onCursorChange(const std::string& name); + void onKeyFocusChanged(MyGUI::Widget* widget); }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 00c520de9..f19f63458 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1,16 +1,10 @@ #include "inputmanagerimp.hpp" -#if defined(__APPLE__) && !defined(__LP64__) -#include -#endif - #include #include #include -#include - #include #include #include @@ -25,13 +19,74 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwgui/bookwindow.hpp" + +using namespace ICS; + +namespace +{ + std::vector utf8ToUnicode(const std::string& utf8) + { + std::vector unicode; + size_t i = 0; + while (i < utf8.size()) + { + unsigned long uni; + size_t todo; + unsigned char ch = utf8[i++]; + if (ch <= 0x7F) + { + uni = ch; + todo = 0; + } + else if (ch <= 0xBF) + { + throw std::logic_error("not a UTF-8 string"); + } + else if (ch <= 0xDF) + { + uni = ch&0x1F; + todo = 1; + } + else if (ch <= 0xEF) + { + uni = ch&0x0F; + todo = 2; + } + else if (ch <= 0xF7) + { + uni = ch&0x07; + todo = 3; + } + else + { + throw std::logic_error("not a UTF-8 string"); + } + for (size_t j = 0; j < todo; ++j) + { + if (i == utf8.size()) + throw std::logic_error("not a UTF-8 string"); + unsigned char ch = utf8[i++]; + if (ch < 0x80 || ch > 0xBF) + throw std::logic_error("not a UTF-8 string"); + uni <<= 6; + uni += ch & 0x3F; + } + if (uni >= 0xD800 && uni <= 0xDFFF) + throw std::logic_error("not a UTF-8 string"); + if (uni > 0x10FFFF) + throw std::logic_error("not a UTF-8 string"); + unicode.push_back(uni); + } + return unicode; + } +} 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) @@ -44,89 +99,37 @@ namespace MWInput , mMouseWheel(0) , mDragDrop(false) , mGuiCursorEnabled(false) - , mDebug(debug) , mUserFile(userFile) , mUserFileExists(userFileExists) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) , mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input")) - , mUIYMultiplier (Settings::Manager::getFloat("ui y multiplier", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) , mAlwaysRunActive(false) { - Ogre::RenderWindow* window = mOgre.getWindow (); - size_t windowHnd; - resetIdleTime(); + Ogre::RenderWindow* window = ogre.getWindow (); - window->getCustomAttribute("WINDOW", &windowHnd); + mInputManager = new SFO::InputWrapper(mOgre.getSDLWindow(), mOgre.getWindow()); + mInputManager->setMouseEventCallback (this); + mInputManager->setKeyboardEventCallback (this); + mInputManager->setWindowEventCallback(this); - 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 (mDebug) - { - #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"))); - #endif - } -#if defined OIS_LINUX_PLATFORM - 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 }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - 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); + std::string file = userFileExists ? userFile : ""; + mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); adjustMouseRegion (window->getWidth(), window->getHeight()); - MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mMouse->getMouseState ().Z.abs); - - std::string file = mUserFileExists ? mUserFile : ""; - mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); + MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, 0); loadKeyDefaults(); for (int i = 0; i < A_Last; ++i) { - mInputCtrl->getChannel (i)->addListener (this); + mInputBinder->getChannel (i)->addListener (this); } mControlSwitch["playercontrols"] = true; @@ -142,13 +145,11 @@ namespace MWInput InputManager::~InputManager() { - mInputCtrl->save (mUserFile); + mInputBinder->save (mUserFile); - delete mInputCtrl; + delete mInputBinder; - mInputManager->destroyInputObject(mKeyboard); - mInputManager->destroyInputObject(mMouse); - OIS::InputManager::destroyInputSystem(mInputManager); + delete mInputManager; } void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) @@ -252,9 +253,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 MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX+1), int(mMouseY+1), mMouseWheel); @@ -262,8 +261,8 @@ 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, // by doing this after the input events are handled we @@ -272,6 +271,25 @@ namespace MWInput // event callbacks (which may crash) mWindows.update(); + bool main_menu = mWindows.containsMode(MWGui::GM_MainMenu); + + bool was_relative = mInputManager->getMouseRelative(); + bool is_relative = !mWindows.isGuiMode(); + + // 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 let the mouse escape in the main menu + mInputManager->setGrabPointer(!main_menu); + + //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); + } + // Disable movement in Gui mode if (mWindows.isGuiMode()) return; @@ -343,7 +361,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) { @@ -382,11 +400,11 @@ namespace MWInput void InputManager::changeInputMode(bool guiMode) { - MWBase::Environment::get().getWindowManager()->setMouseVisible(guiMode); mGuiCursorEnabled = guiMode; mMouseLookEnabled = !guiMode; if (guiMode) mWindows.showCrosshair(false); + mWindows.setCursorVisible(guiMode); // if not in gui mode, the camera decides whether to show crosshair or not. } @@ -443,48 +461,54 @@ namespace MWInput void InputManager::adjustMouseRegion(int width, int height) { - const OIS::MouseState &ms = mMouse->getMouseState(); - ms.width = width; - ms.height = height; + mInputBinder->adjustMouseRegion(width, height); } - bool InputManager::keyPressed( const OIS::KeyEvent &arg ) + bool InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { - if(arg.key == OIS::KC_RETURN + mInputBinder->keyPressed (arg); + + if(arg.keysym.sym == SDLK_RETURN && MWBase::Environment::get().getWindowManager()->isGuiMode()) { // Pressing enter when a messagebox is prompting for "ok" will activate the ok button MWBase::Environment::get().getWindowManager()->enterPressed(); } - mInputCtrl->keyPressed (arg); - unsigned int text = arg.text; -#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)) { - text = 0; - } -#endif + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.key), text); + if (kc != OIS::KC_UNASSIGNED) + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); + return true; + } + + void InputManager::textInput(const SDL_TextInputEvent &arg) + { + const char* text = &arg.text[0]; + std::vector unicode = utf8ToUnicode(std::string(text)); + for (std::vector::iterator it = unicode.begin(); it != unicode.end(); ++it) + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it); + } + + bool InputManager::keyReleased(const SDL_KeyboardEvent &arg ) + { + mInputBinder->keyReleased (arg); + + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); + + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)); return true; } - bool InputManager::keyReleased( const OIS::KeyEvent &arg ) + bool InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { - mInputCtrl->keyReleased (arg); + mInputBinder->mousePressed (arg, id); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key)); + if (id != SDL_BUTTON_LEFT && id != SDL_BUTTON_RIGHT) + return true; // MyGUI has no use for these events - return true; - } - - bool InputManager::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) - { - 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) { @@ -498,18 +522,18 @@ 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); + mInputBinder->mouseReleased (arg, id); - MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id)); + MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); return true; } - bool InputManager::mouseMoved( const OIS::MouseEvent &arg ) + bool InputManager::mouseMoved(const SFO::MouseMotionEvent &arg ) { - mInputCtrl->mouseMoved (arg); + mInputBinder->mouseMoved (arg); resetIdleTime (); @@ -519,21 +543,32 @@ 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 = 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))); - mMouseWheel = arg.state.Z.abs; + + mMouseWheel = int(arg.z); MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); + + //if the player is reading a book and flicking the mouse wheel + if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Book && arg.zrel) + { + if (arg.zrel < 0) + MWBase::Environment::get().getWindowManager()->getBookWindow()->nextPage(); + else + MWBase::Environment::get().getWindowManager()->getBookWindow()->prevPage(); + } } if (mMouseLookEnabled) { resetIdleTime(); - 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); + double x = arg.xrel * mCameraSensitivity * (1.0f/256.f); + double y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier; float scale = MWBase::Environment::get().getFrameDuration(); if(scale <= 0.0f) scale = 1.0f; @@ -545,26 +580,37 @@ namespace MWInput // 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); + mPlayer.yaw(x/scale); + mPlayer.pitch(-y/scale); } - if (arg.state.Z.rel) - MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); + if (arg.zrel) + MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.zrel); } return true; } + bool InputManager::windowFocusChange(bool have_focus) + { + return true; + } + + bool InputManager::windowVisibilityChange(bool visible) + { + //TODO: Pause game? + return true; + } + void InputManager::toggleMainMenu() { if (MyGUI::InputManager::getInstance ().isModalAny()) return; - if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) - mWindows.popGuiMode(); - else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) + 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); } @@ -656,7 +702,7 @@ namespace MWInput // Toggle between game mode and journal mode bool gameMode = !mWindows.isGuiMode(); - if(gameMode) + if(gameMode && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) { MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); mWindows.pushGuiMode(MWGui::GM_Journal); @@ -729,7 +775,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) @@ -738,67 +784,67 @@ 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_Run] = OIS::KC_LSHIFT; - defaultKeyBindings[A_Sneak] = 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_AlwaysRun] = OIS::KC_Y; + 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_Run] = SDLK_LSHIFT; + defaultKeyBindings[A_Sneak] = 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_PRINTSCREEN; + defaultKeyBindings[A_ToggleHUD] = SDLK_F12; + defaultKeyBindings[A_AlwaysRun] = SDLK_y; 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) { 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) == OIS::KC_UNASSIGNED - && 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); } } } @@ -845,15 +891,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) != OIS::KC_UNASSIGNED) - 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}"; } @@ -896,9 +942,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 @@ -909,11 +955,11 @@ 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) { - //Disallow binding escape key, and unassigned keys - if(key==OIS::KC_ESCAPE || key==OIS::KC_UNASSIGNED) - return + //Disallow binding escape key + if(key==SDLK_ESCAPE) + return; clearAllBindings(control); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); @@ -963,10 +1009,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) != OIS::KC_UNASSIGNED) - 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 } @@ -975,4 +1021,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 8aa0d32ad..f463de811 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -6,6 +6,7 @@ #include #include "../mwbase/inputmanager.hpp" +#include namespace OEngine { @@ -35,16 +36,11 @@ namespace ICS class InputControlSystem; } -namespace OIS +namespace MyGUI { - class Keyboard; - class Mouse; - class InputManager; + class MouseButton; } -#include -#include - #include #include @@ -54,13 +50,18 @@ 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 SFO::KeyListener, + public SFO::MouseListener, + public SFO::WindowListener, + public ICS::ChannelListener, + public ICS::DetectingBindingListener { public: InputManager(OEngine::Render::OgreRenderer &_ogre, MWWorld::Player&_player, MWBase::WindowManager &_windows, - bool debug, OMW::Engine& engine, const std::string& userFile, bool userFileExists); @@ -85,12 +86,16 @@ 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 void textInput (const SDL_TextInputEvent &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 SFO::MouseMotionEvent &arg ); + + virtual bool windowVisibilityChange( bool visible ); + virtual bool windowFocusChange( bool have_focus ); virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue); @@ -98,7 +103,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); @@ -123,11 +128,10 @@ namespace MWInput MWBase::WindowManager &mWindows; OMW::Engine& mEngine; - ICS::InputControlSystem* mInputCtrl; + ICS::InputControlSystem* mInputBinder; - OIS::Keyboard* mKeyboard; - OIS::Mouse* mMouse; - OIS::InputManager* mInputManager; + + SFO::InputWrapper* mInputManager; std::string mUserFile; @@ -138,7 +142,6 @@ namespace MWInput float mCameraSensitivity; float mUISensitivity; float mCameraYMultiplier; - float mUIYMultiplier; float mPreviewPOVDelay; float mTimeIdle; @@ -150,7 +153,6 @@ namespace MWInput float mMouseX; float mMouseY; int mMouseWheel; - bool mDebug; bool mUserFileExists; bool mAlwaysRunActive; @@ -158,6 +160,7 @@ namespace MWInput private: void adjustMouseRegion(int width, int height); + MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); void resetIdleTime(); void updateIdleTime(float dt); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 4db574cb8..e85aa9b83 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -29,8 +29,11 @@ namespace MWMechanics calculateCreatureStatModifiers (ptr); // AI - CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); - creatureStats.getAiSequence().execute (ptr); + if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); + creatureStats.getAiSequence().execute (ptr); + } } void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) @@ -309,4 +312,12 @@ namespace MWMechanics if(iter != mActors.end()) iter->second.skipAnim(); } + + bool Actors::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName) + { + PtrControllerMap::iterator iter = mActors.find(ptr); + if(iter != mActors.end()) + return iter->second.isAnimPlaying(groupName); + return false; + } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index c01d63093..386840e3a 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -82,6 +82,7 @@ namespace MWMechanics void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); void skipAnimation(const MWWorld::Ptr& ptr); + bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName); }; } diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 7c28dd216..6af87e8bd 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -1,6 +1,5 @@ #include "aiescort.hpp" -#include "character.hpp" #include "movement.hpp" #include "../mwworld/class.hpp" @@ -10,16 +9,13 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include -#include -#include "boost/tuple/tuple.hpp" - namespace { float sgn(float a) { - if(a>0) return 1.; - else return -1.; + if(a > 0) + return 1.0; + return -1.0; } } @@ -29,74 +25,73 @@ namespace TODO: Take account for actors being in different cells. */ -MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x, float y, float z) -: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration) +namespace MWMechanics { - mMaxDist = 470; - - // The CS Help File states that if a duration is givin, the AI package will run for that long - // BUT if a location is givin, it "trumps" the duration so it will simply escort to that location. - if(mX != 0 || mY != 0 || mZ != 0) - mDuration = 0; - - else + AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z) + : mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration) { - MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); - } -} + mMaxDist = 470; -MWMechanics::AiEscort::AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z) -: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration) -{ - mMaxDist = 470; + // The CS Help File states that if a duration is givin, the AI package will run for that long + // BUT if a location is givin, it "trumps" the duration so it will simply escort to that location. + if(mX != 0 || mY != 0 || mZ != 0) + mDuration = 0; - // The CS Help File states that if a duration is givin, the AI package will run for that long - // BUT if a location is givin, it "trumps" the duration so it will simply escort to that location. - if(mX != 0 || mY != 0 || mZ != 0) - mDuration = 0; - - else - { - MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); - } -} - - -MWMechanics::AiEscort *MWMechanics::AiEscort::clone() const -{ - return new AiEscort(*this); -} - -bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) -{ - // If AiEscort has ran for as long or longer then the duration specified - // and the duration is not infinite, the package is complete. - if(mDuration != 0) - { - MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp(); - unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100); - std::cout << "AiEscort: " << currentSecond << " time: " << currentSecond - mStartingSecond << std::endl; - if(currentSecond - mStartingSecond >= mDuration) + else { - return true; + MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); } } - 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(); - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z) + : mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration) + { + mMaxDist = 470; + // The CS Help File states that if a duration is givin, the AI package will run for that long + // BUT if a location is givin, it "trumps" the duration so it will simply escort to that location. + if(mX != 0 || mY != 0 || mZ != 0) + mDuration = 0; + + else + { + MWWorld::TimeStamp startTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartingSecond = ((startTime.getHour() - int(startTime.getHour())) * 100); + } + } + + + AiEscort *MWMechanics::AiEscort::clone() const + { + return new AiEscort(*this); + } + + bool AiEscort::execute (const MWWorld::Ptr& actor) + { + // If AiEscort has ran for as long or longer then the duration specified + // and the duration is not infinite, the package is complete. + if(mDuration != 0) + { + MWWorld::TimeStamp current = MWBase::Environment::get().getWorld()->getTimeStamp(); + unsigned int currentSecond = ((current.getHour() - int(current.getHour())) * 100); + if(currentSecond - mStartingSecond >= mDuration) + return true; + } + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); 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 AiEscort. // FIXME: This *should* pause the AiEscort package instead of terminating it. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200)) + if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / + 2.0 - 200)) { MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; @@ -107,7 +102,8 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) 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 AiEscort. // FIXME: This *should* pause the AiEscort package instead of terminating it. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200)) + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / + 2.0 - 200)) { MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; @@ -115,68 +111,70 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) } - 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()) + if(!mPathFinder.isPathConstructed() || cellChange) { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + 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; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true); } - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; + if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + return true; + } - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false); + const float* const leaderPos = actor.getRefData().getPosition().pos; + const float* const followerPos = follower.getRefData().getPosition().pos; + double differenceBetween[3]; - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); + for (short counter = 0; counter < 3; counter++) + differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]); + + float distanceBetweenResult = + (differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * + differenceBetween[2]); + + if(distanceBetweenResult <= mMaxDist * mMaxDist) + { + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + mMaxDist = 470; + } + else + { + // Stop moving if the player is to far away + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + mMaxDist = 330; + } + + return false; } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) + int AiEscort::getTypeId() const { - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - return true; + return 2; } - - const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false); - const float* const leaderPos = actor.getRefData().getPosition().pos; - const float* const followerPos = follower.getRefData().getPosition().pos; - double differenceBetween[3]; - - for (short i = 0; i < 3; ++i) - differenceBetween[i] = (leaderPos[i] - followerPos[i]); - - float distanceBetweenResult = - (differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * differenceBetween[2]); - - if(distanceBetweenResult <= mMaxDist * mMaxDist) - { - 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).mPosition[1] = 1; - mMaxDist = 470; - } - else - { - // Stop moving if the player is to far away - MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - mMaxDist = 330; - } - - return false; -} - -int MWMechanics::AiEscort::getTypeId() const -{ - return 2; } diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index 667b88e31..3ae604035 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -2,30 +2,9 @@ #define GAME_MWMECHANICS_AIESCORT_H #include "aipackage.hpp" -#include "pathfinding.hpp" #include -/* From CS: -Escort - -Makes the actor escort another actor to a location or for a specified period of time. During this time the actor will also protect the actor it is escorting. - -If you are not doing this package with the player as the target, you’ll want to also put a follow package on the target Actor, since escorting an actor makes the escorter wait for the other actor. If the Target does not know they are supposed to follow, the escorter will most likely just stand there. - -Target: The ActorID to Escort. Remember that since all ActorIDs share the same AI packages, putting this on an Actor with multiple references will cause ALL references of that actor to attempt to escort the same actor. Thus, this type of AI should only be placed on specific or unique sets of Actors. - -Duration: The duration the actor should escort for. Trumped by providing a location. - -Escort to: Check this to use location data for the escort. - -Cell: The Cell to escort to. - -XYZ: Like Travel, specify the XYZ location to escort to. - -View Location: A red X will appear in the render window that you can move around with the standard render window object controls. Place the X on the escort destination. - - -*/ +#include "pathfinding.hpp" namespace MWMechanics { diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b22185667..90365c16b 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,54 +1,48 @@ #include "aitravel.hpp" -#include -#include "character.hpp" +#include "movement.hpp" -#include "../mwworld/class.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" -#include "movement.hpp" +#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include -#include -#include "boost/tuple/tuple.hpp" - namespace { float sgn(float a) { - if(a>0) return 1.; - else return -1.; + if(a > 0) + return 1.0; + return -1.0; } } namespace MWMechanics { - AiTravel::AiTravel(float x, float y, float z) - : mX(x),mY(y),mZ(z),mPathFinder() + : mX(x),mY(y),mZ(z),mPathFinder() { } - AiTravel * AiTravel::clone() const + AiTravel *MWMechanics::AiTravel::clone() const { return new AiTravel(*this); } bool AiTravel::execute (const MWWorld::Ptr& actor) { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; 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. - 200)) + if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / + 2.0 - 200)) { MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; @@ -58,19 +52,21 @@ namespace MWMechanics { 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. - 200)) + if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / + 2.0 - 200)) { MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } - if(!mPathFinder.isPathConstructed() ||cellChange) + 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; @@ -87,16 +83,17 @@ namespace MWMechanics start.mY = pos.pos[1]; start.mZ = pos.pos[2]; - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); + mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true); } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) + + if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) { 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); + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; return false; @@ -106,5 +103,5 @@ namespace MWMechanics { return 1; } - } + diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 52b41850f..6eb9af8ce 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -2,6 +2,7 @@ #define GAME_MWMECHANICS_AITRAVEL_H #include "aipackage.hpp" + #include "pathfinding.hpp" namespace MWMechanics @@ -25,10 +26,7 @@ namespace MWMechanics int cellX; int cellY; - //bool isPathConstructed; - //std::list mPath; PathFinder mPathFinder; - }; } diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 3cd78a933..8f7926236 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -1,23 +1,337 @@ #include "aiwander.hpp" -#include -MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle): - mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle) +#include "movement.hpp" + +#include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" + +#include + +namespace { + float sgn(float a) + { + if(a > 0) + return 1.0; + return -1.0; + } } -MWMechanics::AiPackage * MWMechanics::AiWander::clone() const +namespace MWMechanics { - return new AiWander(*this); + AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): + mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat) + { + for(unsigned short counter = 0; counter < mIdle.size(); counter++) + { + if(mIdle[counter] >= 127 || mIdle[counter] < 0) + mIdle[counter] = 0; + } + + if(mDistance < 0) + mDistance = 0; + if(mDuration < 0) + mDuration = 0; + if(mDuration == 0) + mTimeOfDay = 0; + + srand(time(NULL)); + mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mPlayedIdle = 0; + mPathgrid = NULL; + mIdleChanceMultiplier = + MWBase::Environment::get().getWorld()->getStore().get().find("fIdleChanceMultiplier")->getFloat(); + + mStoredAvailableNodes = false; + mChooseAction = true; + mIdleNow = false; + mMoveNow = false; + mWalking = false; + } + + AiPackage * MWMechanics::AiWander::clone() const + { + return new AiWander(*this); + } + + bool AiWander::execute (const MWWorld::Ptr& actor) + { + if(mDuration) + { + // End package if duration is complete or mid-night hits: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + if(currentTime.getHour() >= mStartTime.getHour() + mDuration) + { + if(!mRepeat) + { + stopWalking(actor); + return true; + } + else + mStartTime = currentTime; + } + else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) + { + if(!mRepeat) + { + stopWalking(actor); + return true; + } + else + mStartTime = currentTime; + } + } + + ESM::Position pos = actor.getRefData().getPosition(); + + if(!mStoredAvailableNodes) + { + mStoredAvailableNodes = true; + mPathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + mCellX = actor.getCell()->mCell->mData.mX; + mCellY = actor.getCell()->mCell->mData.mY; + + if(!mPathgrid) + mDistance = 0; + else if(mPathgrid->mPoints.empty()) + mDistance = 0; + + if(mDistance) + { + mXCell = 0; + mYCell = 0; + if(actor.getCell()->mCell->isExterior()) + { + mXCell = mCellX * ESM::Land::REAL_SIZE; + mYCell = mCellY * ESM::Land::REAL_SIZE; + } + + Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos); + npcPos[0] = npcPos[0] - mXCell; + npcPos[1] = npcPos[1] - mYCell; + + for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++) + { + Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY, + mPathgrid->mPoints[counter].mZ); + if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) + mAllowedNodes.push_back(mPathgrid->mPoints[counter]); + } + if(!mAllowedNodes.empty()) + { + Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); + float closestNode = npcPos.squaredDistance(firstNodePos); + unsigned int index = 0; + for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) + { + Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, + mAllowedNodes[counterThree].mZ); + float tempDist = npcPos.squaredDistance(nodePos); + if(tempDist < closestNode) + index = counterThree; + } + mCurrentNode = mAllowedNodes[index]; + mAllowedNodes.erase(mAllowedNodes.begin() + index); + } + + if(mAllowedNodes.empty()) + mDistance = 0; + } + } + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY; + + 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 AiWander. + // FIXME: This *should* pause the AiWander package instead of terminating it. + if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / + 2.0 - 200)) + { + stopWalking(actor); + 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 AiWander. + // FIXME: This *should* pause the AiWander package instead of terminating it. + if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / + 2.0 - 200)) + { + stopWalking(actor); + return true; + } + } + + // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. + if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY))) + mDistance = 0; + + if(mChooseAction) + { + mPlayedIdle = 0; + unsigned short idleRoll = 0; + + for(unsigned int counter = 1; counter < mIdle.size(); counter++) + { + unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter]; + unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier)); + if(randSelect < idleChance && randSelect > idleRoll) + { + mPlayedIdle = counter; + idleRoll = randSelect; + } + } + + if(!mPlayedIdle && mDistance) + { + mChooseAction = false; + mMoveNow = true; + } + else + { + // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartTime = currentTime; + playIdle(actor, mPlayedIdle + 1); + mChooseAction = false; + mIdleNow = true; + } + } + + if(mIdleNow) + { + if(!checkIdle(actor, mPlayedIdle + 1)) + { + mPlayedIdle = 0; + mIdleNow = false; + mChooseAction = true; + } + } + + if(mMoveNow && mDistance) + { + if(!mPathFinder.isPathConstructed()) + { + unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); + Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ); + + ESM::Pathgrid::Point dest; + dest.mX = destNodePos[0] + mXCell; + dest.mY = destNodePos[1] + mYCell; + dest.mZ = destNodePos[2]; + + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, false); + + if(mPathFinder.isPathConstructed()) + { + // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): + ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + mAllowedNodes.push_back(mCurrentNode); + mCurrentNode = temp; + + mMoveNow = false; + mWalking = true; + } + // Choose a different node and delete this one from possible nodes because it is uncreachable: + else + mAllowedNodes.erase(mAllowedNodes.begin() + randNode); + } + } + + if(mWalking) + { + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle,false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; + + // Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be + // at the same path node at the same time and both will complete instead of endlessly walking into eachother: + Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ); + Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); + actorPos[0] = actorPos[0] - mXCell; + actorPos[1] = actorPos[1] - mYCell; + float distance = actorPos.squaredDistance(destNodePos); + + if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) + { + stopWalking(actor); + mMoveNow = false; + mWalking = false; + mChooseAction = true; + } + } + + return false; + } + + int AiWander::getTypeId() const + { + return 0; + } + + void AiWander::stopWalking(const MWWorld::Ptr& actor) + { + mPathFinder.clearPath(); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + } + + void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) + { + if(idleSelect == 2) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1); + else if(idleSelect == 3) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1); + else if(idleSelect == 4) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1); + else if(idleSelect == 5) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1); + else if(idleSelect == 6) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1); + else if(idleSelect == 7) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1); + else if(idleSelect == 8) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1); + else if(idleSelect == 9) + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1); + } + + bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) + { + if(idleSelect == 2) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2"); + else if(idleSelect == 3) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3"); + else if(idleSelect == 4) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4"); + else if(idleSelect == 5) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5"); + else if(idleSelect == 6) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6"); + else if(idleSelect == 7) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7"); + else if(idleSelect == 8) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8"); + else if(idleSelect == 9) + return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9"); + else + return false; + } } -bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) -{ - // Return completed - return true; -} - -int MWMechanics::AiWander::getTypeId() const -{ - return 0; -} diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index a71858feb..c82ccc215 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -4,26 +4,61 @@ #include "aipackage.hpp" #include +#include "pathfinding.hpp" + +#include "../mwworld/timestamp.hpp" + namespace MWMechanics { - class AiWander : public AiPackage { - public: + public: - AiWander(int distance, int duration, int timeOfDay, const std::vector& idle); - virtual AiPackage *clone() const; - virtual bool execute (const MWWorld::Ptr& actor); - ///< \return Package completed? - virtual int getTypeId() const; - ///< 0: Wander + AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat); + virtual AiPackage *clone() const; + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + virtual int getTypeId() const; + ///< 0: Wander + + private: + void stopWalking(const MWWorld::Ptr& actor); + void playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); + bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); + + int mDistance; + int mDuration; + int mTimeOfDay; + std::vector mIdle; + bool mRepeat; + + float mX; + float mY; + float mZ; + + int mCellX; + int mCellY; + float mXCell; + float mYCell; + + bool mStoredAvailableNodes; + bool mChooseAction; + bool mIdleNow; + bool mMoveNow; + bool mWalking; + + float mIdleChanceMultiplier; + unsigned short mPlayedIdle; + + MWWorld::TimeStamp mStartTime; + + std::vector mAllowedNodes; + ESM::Pathgrid::Point mCurrentNode; + + PathFinder mPathFinder; + const ESM::Pathgrid *mPathgrid; - private: - int mDistance; - int mDuration; - int mTimeOfDay; - std::vector mIdle; }; - } +} #endif diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 31ba83392..d3dbb9325 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -179,6 +179,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mSkipAnim(false) , mSecondsOfRunning(0) , mSecondsOfSwimming(0) + , mUpdateWeapon(true) { if(!mAnimation) return; @@ -407,6 +408,13 @@ void CharacterController::update(float duration, Movement &movement) else weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if(mUpdateWeapon) + { + mWeaponType = weaptype; + forceStateUpdate(); + mUpdateWeapon = false; + } + if(weaptype != mWeaponType) { std::string weapgroup; @@ -454,6 +462,10 @@ void CharacterController::update(float duration, Movement &movement) mAnimation->disable("torch"); } } + else if (cls.getCreatureStats(mPtr).isDead()) + { + MWBase::Environment::get().getWorld()->enableActorCollision(mPtr, false); + } if(mAnimation && !mSkipAnim) { @@ -461,15 +473,18 @@ void CharacterController::update(float duration, Movement &movement) Ogre::Vector3 moved = mAnimation->runAnimation(duration); // Ensure we're moving in generally the right direction - if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) || - (movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f)) - moved.x = movement.mPosition[0]; - if((movement.mPosition[1] < 0.0f && movement.mPosition[1] < moved.y*2.0f) || - (movement.mPosition[1] > 0.0f && movement.mPosition[1] > moved.y*2.0f)) - moved.y = movement.mPosition[1]; - if((movement.mPosition[2] < 0.0f && movement.mPosition[2] < moved.z*2.0f) || - (movement.mPosition[2] > 0.0f && movement.mPosition[2] > moved.z*2.0f)) - moved.z = movement.mPosition[2]; + if (speed > 0.f) + { + if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) || + (movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f)) + moved.x = movement.mPosition[0]; + if((movement.mPosition[1] < 0.0f && movement.mPosition[1] < moved.y*2.0f) || + (movement.mPosition[1] > 0.0f && movement.mPosition[1] > moved.y*2.0f)) + moved.y = movement.mPosition[1]; + if((movement.mPosition[2] < 0.0f && movement.mPosition[2] < moved.z*2.0f) || + (movement.mPosition[2] > 0.0f && movement.mPosition[2] > moved.z*2.0f)) + moved.z = movement.mPosition[2]; + } movement.mPosition[0] = moved.x; movement.mPosition[1] = moved.y; @@ -509,6 +524,14 @@ void CharacterController::skipAnim() mSkipAnim = true; } +bool CharacterController::isAnimPlaying(const std::string &groupName) +{ + if(mAnimation == NULL) + return false; + else + return mAnimation->isPlaying(groupName); +} + void CharacterController::clearAnimQueue() { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 7ffefab47..cf5d6e823 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -104,6 +104,9 @@ class CharacterController WeaponType mWeaponType; bool mSkipAnim; + // Workaround for playing weapon draw animation and sound when going to new cell + bool mUpdateWeapon; + // counted for skill increase float mSecondsOfSwimming; float mSecondsOfRunning; @@ -125,6 +128,7 @@ public: void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); + bool isAnimPlaying(const std::string &groupName); void setState(CharacterState state); CharacterState getState() const diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index ded75f03a..faa450df7 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -12,7 +12,7 @@ namespace MWMechanics { Enchanting::Enchanting(): - mEnchantType(0) + mCastStyle(ESM::Enchantment::CastOnce) {} void Enchanting::setOldItem(MWWorld::Ptr oldItem) @@ -41,9 +41,9 @@ namespace MWMechanics mEffectList=effectList; } - int Enchanting::getEnchantType() const + int Enchanting::getCastStyle() const { - return mEnchantType; + return mCastStyle; } void Enchanting::setSoulGem(MWWorld::Ptr soulGem) @@ -74,12 +74,12 @@ namespace MWMechanics MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } - if(mEnchantType==3) + if(mCastStyle==ESM::Enchantment::ConstantEffect) { enchantment.mData.mCharge=0; } - enchantment.mData.mType = mEnchantType; - enchantment.mData.mCost = getEnchantCost(); + enchantment.mData.mType = mCastStyle; + enchantment.mData.mCost = getEnchantPoints(); enchantment.mEffects = mEffectList; const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment); @@ -98,87 +98,142 @@ namespace MWMechanics return true; } - void Enchanting::nextEnchantType() + void Enchanting::nextCastStyle() { - mEnchantType++; if (itemEmpty()) { - mEnchantType = 0; + mCastStyle = ESM::Enchantment::WhenUsed; return; } - if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) - { - int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); - switch(mEnchantType) + + const bool powerfulSoul = getGemCharge() >= \ + MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); + if ((mObjectType == typeid(ESM::Armor).name()) || (mObjectType == typeid(ESM::Clothing).name())) + { // Armor or Clothing + switch(mCastStyle) { - case 1: - mEnchantType = 2; - case 3: - if(getGemCharge() 2 or (2 + 0) == (1 + 2) => 3 + * + * Formula on UESPWiki is not entirely correct. + */ + float Enchanting::getEnchantPoints() const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - float cost = 0; - std::vector mEffects = mEffectList.mList; - int i=mEffects.size(); - if(i<=0) + if (mEffectList.mList.empty()) + // No effects added, cost = 0 return 0; - /* - Formula from http://www.uesp.net/wiki/Morrowind:Enchant - */ + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + std::vector mEffects = mEffectList.mList; + + float enchantmentCost = 0; + int effectsLeftCnt = mEffects.size(); + float baseCost, magnitudeCost, areaCost; + int magMin, magMax, area; for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { - const ESM::MagicEffect* effect = store.get().find(it->mEffectID); + baseCost = (store.get().find(it->mEffectID))->mData.mBaseCost; + // To reflect vanilla behavior + magMin = (it->mMagnMin == 0) ? 1 : it->mMagnMin; + magMax = (it->mMagnMax == 0) ? 1 : it->mMagnMax; + area = (it->mArea == 0) ? 1 : it->mArea; - float cost1 = ((it->mMagnMin + it->mMagnMax)*it->mDuration*effect->mData.mBaseCost*0.025); - - float cost2 = (std::max(1, it->mArea)*0.125*effect->mData.mBaseCost); - - if(mEnchantType==3) + if (mCastStyle == ESM::Enchantment::ConstantEffect) { - int constDurationMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantDurationMult")->getFloat(); - cost1 *= constDurationMultipler; - cost2 *= 2; + magnitudeCost = (magMin + magMax) * baseCost * 2.5; + } + else + { + magnitudeCost = (magMin + magMax) * it->mDuration * baseCost * 0.025; + if(it->mRange == ESM::RT_Target) + magnitudeCost *= 1.5; } - if(effect->mData.mFlags & ESM::MagicEffect::CastTarget) - cost1 *= 1.5; - float fullcost = cost1+cost2; - fullcost*= i; - i--; + areaCost = area * 0.025 * baseCost; + if (it->mRange == ESM::RT_Target) + areaCost *= 1.5; - cost+=fullcost; + enchantmentCost += (magnitudeCost + areaCost) * effectsLeftCnt; + --effectsLeftCnt; } - return cost; + + return enchantmentCost; } + + float Enchanting::getCastCost() const + { + if (mCastStyle == ESM::Enchantment::ConstantEffect) + return 0; + + const float enchantCost = getEnchantPoints(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats &stats = MWWorld::Class::get(player).getNpcStats(player); + int eSkill = stats.getSkill(ESM::Skill::Enchant).getModified(); + + /* + * Each point of enchant skill above/under 10 subtracts/adds + * one percent of enchantment cost while minimum is 1. + */ + const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10); + + return (castCost < 1) ? 1 : castCost; + } + + 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); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantPoints() * priceMultipler), true); return price; } @@ -201,16 +256,12 @@ namespace MWMechanics } bool Enchanting::soulEmpty() const { - if (mSoulGemPtr.isEmpty()) - return true; - return false; + return mSoulGemPtr.isEmpty(); } bool Enchanting::itemEmpty() const { - if(mOldItemPtr.isEmpty()) - return true; - return false; + return mOldItemPtr.isEmpty(); } void Enchanting::setSelfEnchanting(bool selfEnchanting) @@ -235,8 +286,8 @@ namespace MWMechanics (0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified()) + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); - float chance2 = 2.5 * getEnchantCost(); - if(mEnchantType==3) + float chance2 = 2.5 * getEnchantPoints(); + if(mCastStyle==ESM::Enchantment::ConstantEffect) { float constantChance = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantChanceMult")->getFloat(); chance2 /= constantChance; diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 2831f9ddb..a25fd43ab 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -13,7 +13,7 @@ namespace MWMechanics MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mEnchanter; - int mEnchantType; + int mCastStyle; bool mSelfEnchanting; @@ -33,9 +33,10 @@ namespace MWMechanics void setEffect(ESM::EffectList effectList); void setSoulGem(MWWorld::Ptr soulGem); bool create(); //Return true if created, false if failed. - void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) - int getEnchantType() const; - float getEnchantCost() const; + void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object) + int getCastStyle() const; + float getEnchantPoints() const; + float getCastCost() const; int getEnchantPrice() const; float getMaxEnchantValue() const; int getGemCharge() const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index b83cfb365..29880291d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -668,5 +668,12 @@ namespace MWMechanics else mObjects.skipAnimation(ptr); } + bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName) + { + if(MWWorld::Class::get(ptr).isActor()) + return mActors.checkAnimationPlaying(ptr, groupName); + else + return false; + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index f3a38bf36..95f760d11 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -100,6 +100,7 @@ namespace MWMechanics virtual void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); virtual void skipAnimation(const MWWorld::Ptr& ptr); + virtual bool checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string &groupName); }; } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 62c825be7..986595a9a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -3,164 +3,134 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "OgreMath.h" + #include #include -#include "boost/tuple/tuple.hpp" -#include "OgreMath.h" namespace { - //helpers functions - float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) + struct found_path {}; + + typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, + boost::property, boost::property > + PathGridGraph; + typedef boost::property_map::type WeightMap; + typedef PathGridGraph::vertex_descriptor PointID; + typedef PathGridGraph::edge_descriptor PointConnectionID; + + class goalVisited : public boost::default_dijkstra_visitor { - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); + public: + goalVisited(PointID goal) {mGoal = goal;}; + void examine_vertex(PointID u, const PathGridGraph g) {if(u == mGoal) throw found_path();}; + + private: + PointID mGoal; + }; + + float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z) + { + x -= point.mX; + y -= point.mY; + z -= point.mZ; + return sqrt(x * x + y * y + 0.1 * z * z); } - float distance(ESM::Pathgrid::Point point,float x,float y,float 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)); + x -= point.mX; + y -= point.mY; + z -= point.mZ; + return sqrt(x * x + y * y + z * z); } - float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) + 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 x = a.mX - b.mX; + float y = a.mY - b.mY; + float z = a.mZ - b.mZ; + return sqrt(x * x + y * y + z * z); } static float sgn(float a) { - if(a>0) return 1.; - else return -1.; + if(a > 0) + return 1.0; + return -1.0; } - int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) + int getClosestPoint(const ESM::Pathgrid* grid, float x, float y, float z) { - if(!grid) return -1; - if(grid->mPoints.empty()) return -1; + if(!grid || grid->mPoints.empty()) + return -1; - float m = distance(grid->mPoints[0],x,y,z); - int i0 = 0; + float distanceBetween = distance(grid->mPoints[0], x, y, z); + int closestIndex = 0; - for(unsigned int i=1; imPoints.size();++i) + for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) { - if(distance(grid->mPoints[i],x,y,z)mPoints[counter], x, y, z) < distanceBetween) { - m = distance(grid->mPoints[i],x,y,z); - i0 = i; + distanceBetween = distance(grid->mPoints[counter], x, y, z); + closestIndex = counter; } } - return i0; + + return closestIndex; } - 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::atasr_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; - };*/ - - 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; - }; - - - PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) + PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid, float xCell = 0, float yCell = 0) { PathGridGraph graph; - for(unsigned int i = 0;imPoints.size();++i) + for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) { 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; + graph[pID].mX = pathgrid->mPoints[counter].mX + xCell; + graph[pID].mY = pathgrid->mPoints[counter].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[counter].mZ; } - for(unsigned int i = 0;imEdges.size();++i) + for(unsigned int counterTwo = 0; counterTwo < pathgrid->mEdges.size(); counterTwo++) { - PointID u = pathgrid->mEdges[i].mV0; - PointID v = pathgrid->mEdges[i].mV1; + PointID u = pathgrid->mEdges[counterTwo].mV0; + PointID v = pathgrid->mEdges[counterTwo].mV1; PointConnectionID edge; bool done; - boost::tie(edge,done) = boost::add_edge(u,v,graph); + 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]); - + weightmap[edge] = distance(graph[u], graph[v]); } return graph; } - std::list findPath(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; - try { - boost::dijkstra_shortest_paths - ( - graph, - start, - boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); + try + { + boost::dijkstra_shortest_paths(graph, start, + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))); + } - } catch(found_path fg) { - for(PointID v = end;; v = p[v]) { + 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 - } namespace MWMechanics @@ -170,55 +140,81 @@ namespace MWMechanics mIsPathConstructed = false; } - void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid,float xCell,float yCell) + void PathFinder::clearPath() { - //first check if there is an obstacle - if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX,startPoint.mY,startPoint.mZ, - endPoint.mX,endPoint.mY,endPoint.mZ) ) - { - 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(!mPath.empty()) + mPath.clear(); + mIsPathConstructed = false; + } - if(start != -1 && end != -1) + void PathFinder::buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid, float xCell, float yCell, bool allowShortcuts) + { + if(allowShortcuts) + { + if(MWBase::Environment::get().getWorld()->castRay(startPoint.mX, startPoint.mY, startPoint.mZ, endPoint.mX, endPoint.mY, + endPoint.mZ)) + allowShortcuts = false; + } + + if(!allowShortcuts) + { + int startNode = getClosestPoint(pathGrid, startPoint.mX - xCell, startPoint.mY - yCell,startPoint.mZ); + int endNode = getClosestPoint(pathGrid, endPoint.mX - xCell, endPoint.mY - yCell, endPoint.mZ); + + if(startNode != -1 && endNode != -1) { - PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); - mPath = findPath(start,end,graph); + PathGridGraph graph = buildGraph(pathGrid, xCell, yCell); + mPath = findPath(startNode, endNode, graph); + + if(!mPath.empty()) + { + mPath.push_back(endPoint); + mIsPathConstructed = true; + } } } - mPath.push_back(endPoint); - mIsPathConstructed = true; - } - - float PathFinder::getZAngleToNext(float x,float y,float z) - { - if(mPath.empty()) + else { - return 0;/// shouldn't happen! + mPath.push_back(endPoint); + mIsPathConstructed = true; } - 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(); + + if(mPath.empty()) + mIsPathConstructed = false; } - bool PathFinder::checkIfNextPointReached(float x,float y,float z) + float PathFinder::getZAngleToNext(float x, float y) + { + // This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call + // if otherwise). + if(mPath.empty()) + return 0; + + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + float directionX = nextPoint.mX - x; + float directionY = nextPoint.mY - y; + float directionResult = sqrt(directionX * directionX + directionY * directionY); + + return Ogre::Radian(acos(directionY / directionResult) * sgn(asin(directionX / directionResult))).valueDegrees(); + } + + bool PathFinder::checkPathCompleted(float x, float y, float z) { if(mPath.empty()) - { return true; - } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distanceZCorrected(nextPoint,x,y,z) < 20) + if(distanceZCorrected(nextPoint, x, y, z) < 40) { mPath.pop_front(); if(mPath.empty()) { + mIsPathConstructed = false; return true; } - nextPoint = *mPath.begin(); } + return false; } @@ -226,8 +222,10 @@ namespace MWMechanics { 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 b1bbab37a..1727c650f 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -8,22 +8,24 @@ namespace MWMechanics { class PathFinder { - public: - PathFinder(); + public: + PathFinder(); - void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, - const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); + void clearPath(); + void buildPath(ESM::Pathgrid::Point startPoint, ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid, float xCell = 0, float yCell = 0, bool allowShortcuts = 1); - 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); + bool checkPathCompleted(float x, float y, float z); + ///< \Returns true if the last point of the path has been reached. + float getZAngleToNext(float x, float y); - std::list getPath(); - bool isPathConstructed(); + std::list getPath(); + bool isPathConstructed(); - private: - std::list mPath; - bool mIsPathConstructed; + private: + std::list mPath; + bool mIsPathConstructed; }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index e4bba289f..e9ecedc55 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -230,7 +230,10 @@ namespace MWRender mNode->roll(Ogre::Radian(angle), Ogre::SceneNode::TS_LOCAL); updateCamera(); + } + void RaceSelectionPreview::render() + { mRenderTarget->update(); } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 562cb3784..b2dfc9679 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -93,6 +93,7 @@ namespace MWRender RaceSelectionPreview(); virtual void onSetup(); + void render(); void update(float angle); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 9061f8402..c8b496f6b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -64,13 +64,16 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b { // select best shader mode bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); + bool glES = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL ES") != std::string::npos); // glsl is only supported in opengl mode and hlsl only in direct3d mode. - if (Settings::Manager::getString("shader mode", "General") == "" - || (openGL && Settings::Manager::getString("shader mode", "General") == "hlsl") - || (!openGL && Settings::Manager::getString("shader mode", "General") == "glsl")) + std::string currentMode = Settings::Manager::getString("shader mode", "General"); + if (currentMode == "" + || (openGL && currentMode == "hlsl") + || (!openGL && currentMode == "glsl") + || (glES && currentMode != "glsles")) { - Settings::Manager::setString("shader mode", "General", openGL ? "glsl" : "hlsl"); + Settings::Manager::setString("shader mode", "General", openGL ? (glES ? "glsles" : "glsl") : "hlsl"); } mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); @@ -93,6 +96,8 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b std::string l = Settings::Manager::getString("shader mode", "General"); if (l == "glsl") lang = sh::Language_GLSL; + else if (l == "glsles") + lang = sh::Language_GLSLES; else if (l == "hlsl") lang = sh::Language_HLSL; else @@ -124,7 +129,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b Ogre::TextureManager::getSingleton().setMemoryBudget(126*1024*1024); Ogre::MeshManager::getSingleton().setMemoryBudget(64*1024*1024); - ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); + Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); // disable unsupported effects if (!Settings::Manager::getBool("shaders", "Objects")) @@ -305,7 +310,7 @@ void RenderingManager::update (float duration, bool paused) MWWorld::Ptr player = world->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)); + mRendering.getFader()->setFactor(std::max(0.f, 1.f-(blind / 100.f))); setAmbientMode(); // player position @@ -396,29 +401,24 @@ void RenderingManager::setWaterHeight(const float height) void RenderingManager::skyEnable () { - if(mSkyManager) mSkyManager->enable(); - mOcclusionQuery->setSunNode(mSkyManager->getSunNode()); } void RenderingManager::skyDisable () { - if(mSkyManager) - mSkyManager->disable(); + mSkyManager->disable(); } void RenderingManager::skySetHour (double hour) { - if(mSkyManager) - mSkyManager->setHour(hour); + mSkyManager->setHour(hour); } void RenderingManager::skySetDate (int day, int month) { - if(mSkyManager) - mSkyManager->setDate(day, month); + mSkyManager->setDate(day, month); } int RenderingManager::skyGetMasserPhase() const @@ -433,8 +433,7 @@ int RenderingManager::skyGetSecundaPhase() const } void RenderingManager::skySetMoonColour (bool red){ - if(mSkyManager) - mSkyManager->setMoonColour(red); + mSkyManager->setMoonColour(red); } bool RenderingManager::toggleRenderMode(int mode) @@ -712,7 +711,7 @@ Compositors* RenderingManager::getCompositors() void RenderingManager::processChangedSettings(const Settings::CategorySettingVector& settings) { - bool changeRes = false; + //bool changeRes = false; bool rebuild = false; // rebuild static geometry (necessary after any material changes) for (Settings::CategorySettingVector::const_iterator it=settings.begin(); it != settings.end(); ++it) @@ -726,11 +725,11 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec if (!MWBase::Environment::get().getWorld()->isCellExterior() && !MWBase::Environment::get().getWorld()->isCellQuasiExterior()) configureFog(*MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()); } - else if (it->first == "Video" && ( + /*else if (it->first == "Video" && ( it->second == "resolution x" || it->second == "resolution y" || it->second == "fullscreen")) - changeRes = true; + changeRes = true;*/ else if (it->second == "field of view" && it->first == "General") mRendering.setFov(Settings::Manager::getFloat("field of view", "General")); else if ((it->second == "texture filtering" && it->first == "General") @@ -784,17 +783,24 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec } } + /* if (changeRes) { unsigned int x = Settings::Manager::getInt("resolution x", "Video"); unsigned int y = Settings::Manager::getInt("resolution y", "Video"); + SDL_SetWindowFullscreen(mRendering.getSDLWindow(), 0); + if (x != mRendering.getWindow()->getWidth() || y != mRendering.getWindow()->getHeight()) { + SDL_SetWindowSize(mRendering.getSDLWindow(), x, y); mRendering.getWindow()->resize(x, y); } - mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); + + SDL_SetWindowFullscreen(mRendering.getSDLWindow(), Settings::Manager::getBool("fullscreen", "Video") ? SDL_WINDOW_FULLSCREEN : 0); + //mRendering.getWindow()->setFullscreen(Settings::Manager::getBool("fullscreen", "Video"), x, y); } + */ mWater->processChangedSettings(settings); @@ -817,7 +823,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(); diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 87ae8175d..08642c5a3 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -32,9 +32,24 @@ namespace MWRender extern "C" { -#include -#include -#include + #include + #include + #include + + // From libavformat version 55.0.100 and onward the declaration of av_gettime() is removed from libavformat/avformat.h and moved + // to libavutil/time.h + // https://github.com/FFmpeg/FFmpeg/commit/06a83505992d5f49846c18507a6c3eb8a47c650e + #if AV_VERSION_INT(55, 0, 100) <= AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, LIBAVFORMAT_VERSION_MINOR, LIBAVFORMAT_VERSION_MICRO) + #include + #endif + + // From libavutil version 52.2.0 and onward the declaration of + // AV_CH_LAYOUT_* is removed from libavcodec/avcodec.h and moved to + // libavutil/channel_layout.h + #if AV_VERSION_INT(52, 2, 0) <= AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO) + #include + #endif } #define MAX_AUDIOQ_SIZE (5 * 16 * 1024) diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 65ca3ae21..9f29163af 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -181,19 +181,29 @@ namespace MWScript runtime.pop(); std::vector idleList; + bool repeat = false; - for (int i=2; i<10 && arg0; ++i) + for(int i=1; i < 10 && arg0; ++i) { + if(!repeat) + repeat = true; Interpreter::Type_Integer idleValue = runtime[0].mInteger; idleList.push_back(idleValue); runtime.pop(); --arg0; } + if(arg0) + { + repeat = runtime[0].mInteger != 0; + runtime.pop(); + --arg0; + } + // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i - // FIXME: This can't be right? The headers refuse to build without UINT64_C, // which only gets defined in stdint.h in either C99 mode or with this macro // defined... @@ -12,8 +10,18 @@ extern "C" { #include #include + +// From libavutil version 52.2.0 and onward the declaration of +// AV_CH_LAYOUT_* is removed from libavcodec/avcodec.h and moved to +// libavutil/channel_layout.h +#if AV_VERSION_INT(52, 2, 0) <= AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, LIBAVUTIL_VERSION_MICRO) + #include +#endif } +#include + #include "sound_decoder.hpp" diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index e352b4c82..cd1eb823d 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -125,20 +125,20 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Sneak, sneak); } - void Player::setYaw(float yaw) + void Player::yaw(float yaw) { MWWorld::Ptr ptr = getPlayer(); - MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[2] = yaw; + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[2] += yaw; } - void Player::setPitch(float pitch) + void Player::pitch(float pitch) { MWWorld::Ptr ptr = getPlayer(); - MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[0] = pitch; + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[0] += pitch; } - void Player::setRoll(float roll) + void Player::roll(float roll) { MWWorld::Ptr ptr = getPlayer(); - MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[1] = roll; + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[1] += roll; } void Player::use() diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index fd25f749f..4660c6e9a 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -64,9 +64,9 @@ namespace MWWorld void setRunState(bool run); void setSneak(bool sneak); - void setYaw(float yaw); - void setPitch(float pitch); - void setRoll(float roll); + void yaw(float yaw); + void pitch(float pitch); + void roll(float roll); }; } #endif diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index aec00a8c6..22facdcaf 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -2,6 +2,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" /// FIXME #include "../mwbase/soundmanager.hpp" @@ -353,7 +355,7 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { - + MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.5); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -422,6 +424,7 @@ namespace MWWorld MWBase::Environment::get().getWorld()->adjustSky(); mCellChanged = true; + MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.5); MWBase::Environment::get().getWindowManager ()->loadingDone (); } diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index b49569f24..4ccd0e689 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -273,6 +273,14 @@ namespace MWWorld mStatic[scpt.mId] = scpt; } + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + ESM::StartScript s; + s.load(esm); + s.mId = Misc::StringUtils::toLower(s.mScript); + mStatic[s.mId] = s; + } + template <> class Store : public StoreBase { diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8b3c5f6ff..467d7e7c8 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,8 +1,5 @@ #include "weather.hpp" -#include -#include - #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -91,10 +88,11 @@ float WeatherManager::calculateAngleFade (const std::string& moonName, float ang } WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : - mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), - mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0), - mRemainingTransitionTime(0), mMonth(0), mDay(0), - mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), mRendering(rendering) + mHour(14), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true), + mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), + mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0), + mMonth(0), mDay(0), mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), + mRendering(rendering) { //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); @@ -197,32 +195,31 @@ void WeatherManager::setWeather(const String& weather, bool instant) mFirstUpdate = false; } -WeatherResult WeatherManager::getResult(const String& weather) +void WeatherManager::setResult(const String& weatherType) { - const Weather& current = mWeatherSettings[weather]; - WeatherResult result; + const Weather& current = mWeatherSettings[weatherType]; - result.mCloudTexture = current.mCloudTexture; - result.mCloudBlendFactor = 0; - result.mCloudOpacity = current.mCloudsMaximumPercent; - result.mWindSpeed = current.mWindSpeed; - result.mCloudSpeed = current.mCloudSpeed; - result.mGlareView = current.mGlareView; - result.mAmbientLoopSoundID = current.mAmbientLoopSoundID; - result.mSunColor = current.mSunDiscSunsetColor; - - result.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1); + mResult.mCloudTexture = current.mCloudTexture; + mResult.mCloudBlendFactor = 0; + mResult.mCloudOpacity = current.mCloudsMaximumPercent; + mResult.mWindSpeed = current.mWindSpeed; + mResult.mCloudSpeed = current.mCloudSpeed; + mResult.mGlareView = current.mGlareView; + mResult.mAmbientLoopSoundID = current.mAmbientLoopSoundID; + mResult.mSunColor = current.mSunDiscSunsetColor; - result.mFogDepth = result.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; + mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1); + + mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; // night if (mHour <= mNightEnd || mHour >= mNightStart + 1) { - result.mFogColor = current.mFogNightColor; - result.mAmbientColor = current.mAmbientNightColor; - result.mSunColor = current.mSunNightColor; - result.mSkyColor = current.mSkyNightColor; - result.mNightFade = 1.f; + mResult.mFogColor = current.mFogNightColor; + mResult.mAmbientColor = current.mAmbientNightColor; + mResult.mSunColor = current.mSunNightColor; + mResult.mSkyColor = current.mSkyNightColor; + mResult.mNightFade = 1.f; } // sunrise @@ -233,31 +230,31 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade in float advance = mSunriseTime - mHour; float factor = advance / 0.5f; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); - result.mNightFade = factor; + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; } else //if (mHour >= 6) { // fade out float advance = mHour - mSunriseTime; float factor = advance / 3.f; - result.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); - result.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); - result.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); - result.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); + mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); } } // day else if (mHour >= mDayStart + 1 && mHour <= mDayEnd - 1) { - result.mFogColor = current.mFogDayColor; - result.mAmbientColor = current.mAmbientDayColor; - result.mSunColor = current.mSunDayColor; - result.mSkyColor = current.mSkyDayColor; + mResult.mFogColor = current.mFogDayColor; + mResult.mAmbientColor = current.mAmbientDayColor; + mResult.mSunColor = current.mSunDayColor; + mResult.mSkyColor = current.mSkyDayColor; } // sunset @@ -268,54 +265,51 @@ WeatherResult WeatherManager::getResult(const String& weather) // fade in float advance = (mDayEnd + 1) - mHour; float factor = (advance / 2); - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); } else //if (mHour >= 19) { // fade out float advance = mHour - (mDayEnd + 1); float factor = advance / 2.f; - result.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); - result.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); - result.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); - result.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); - result.mNightFade = factor; + mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); + mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); + mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); + mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); + mResult.mNightFade = factor; } } - - return result; } -WeatherResult WeatherManager::transition(float factor) +void WeatherManager::transition(float factor) { - const WeatherResult& current = getResult(mCurrentWeather); - const WeatherResult& other = getResult(mNextWeather); - WeatherResult result; + setResult(mCurrentWeather); + const WeatherResult current = mResult; + setResult(mNextWeather); + const WeatherResult other = mResult; - result.mCloudTexture = current.mCloudTexture; - result.mNextCloudTexture = other.mCloudTexture; - result.mCloudBlendFactor = factor; + mResult.mCloudTexture = current.mCloudTexture; + mResult.mNextCloudTexture = other.mCloudTexture; + mResult.mCloudBlendFactor = factor; - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); - result.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); - result.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); - result.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); + mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); + mResult.mFogColor = lerp(current.mFogColor, other.mFogColor, factor); + mResult.mSunColor = lerp(current.mSunColor, other.mSunColor, factor); + mResult.mSkyColor = lerp(current.mSkyColor, other.mSkyColor, factor); - result.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); - result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); - result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); - result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); - result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); - result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); - result.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); - result.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); + mResult.mAmbientColor = lerp(current.mAmbientColor, other.mAmbientColor, factor); + mResult.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor, factor); + mResult.mFogDepth = lerp(current.mFogDepth, other.mFogDepth, factor); + mResult.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed, factor); + mResult.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed, factor); + mResult.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity, factor); + mResult.mGlareView = lerp(current.mGlareView, other.mGlareView, factor); + mResult.mNightFade = lerp(current.mNightFade, other.mNightFade, factor); - result.mNight = current.mNight; - - return result; + mResult.mNight = current.mNight; } void WeatherManager::update(float duration) @@ -325,263 +319,227 @@ void WeatherManager::update(float duration) mWeatherUpdateTime -= timePassed; - bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - - if (exterior) - { - std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); - - if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) - { - mCurrentRegion = regionstr; - mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; - - std::string weather = "clear"; - - if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) - weather = mRegionOverrides[regionstr]; - else - { - // get weather probabilities for the current region - const ESM::Region *region = - MWBase::Environment::get().getWorld()->getStore().get().search (regionstr); - - if (region != 0) - { - float clear = region->mData.mClear/255.f; - float cloudy = region->mData.mCloudy/255.f; - float foggy = region->mData.mFoggy/255.f; - float overcast = region->mData.mOvercast/255.f; - float rain = region->mData.mRain/255.f; - float thunder = region->mData.mThunder/255.f; - float ash = region->mData.mAsh/255.f; - float blight = region->mData.mBlight/255.f; - float snow = region->mData.mA/255.f; - float blizzard = region->mData.mB/255.f; - - // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; - - float random = ((rand()%100)/100.f) * total; - - if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "blizzard"; - else if (random >= blight+ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "snow"; - else if (random >= ash+thunder+rain+overcast+foggy+cloudy+clear) - weather = "blight"; - else if (random >= thunder+rain+overcast+foggy+cloudy+clear) - weather = "ashstorm"; - else if (random >= rain+overcast+foggy+cloudy+clear) - weather = "thunderstorm"; - else if (random >= overcast+foggy+cloudy+clear) - weather = "rain"; - else if (random >= foggy+cloudy+clear) - weather = "overcast"; - else if (random >= cloudy+clear) - weather = "foggy"; - else if (random >= clear) - weather = "cloudy"; - else - weather = "clear"; - } - } - - setWeather(weather, false); - } - - WeatherResult result; - - if (mNextWeather != "") - { - mRemainingTransitionTime -= timePassed; - if (mRemainingTransitionTime < 0) - { - mCurrentWeather = mNextWeather; - mNextWeather = ""; - } - } - - if (mNextWeather != "") - result = transition(1 - (mRemainingTransitionTime / (mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600))); - else - result = getResult(mCurrentWeather); - - mWindSpeed = result.mWindSpeed; - - mRendering->configureFog(result.mFogDepth, result.mFogColor); - - // disable sun during night - if (mHour >= mNightStart || mHour <= mSunriseTime) - mRendering->getSkyManager()->sunDisable(); - else - mRendering->getSkyManager()->sunEnable(); - - // sun angle - float height; - - //Day duration - float dayDuration = (mNightStart - 1) - mSunriseTime; - - // rise at 6, set at 20 - if (mHour >= mSunriseTime && mHour <= mNightStart) - height = 1 - std::abs(((mHour - dayDuration) / 7.f)); - else if (mHour > mNightStart) - height = (mHour - mNightStart) / 4.f; - else //if (mHour > 0 && mHour < 6) - height = 1 - (mHour / mSunriseTime); - - int facing = (mHour > 13.f) ? 1 : -1; - - Vector3 final( - -(1 - height) * facing, - -(1 - height) * facing, - height); - mRendering->setSunDirection(final); - - /* - * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish - * for masser and secunda - */ - - float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish"); - float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); - - //moon calculations - float moonHeight; - if (mHour >= fadeInStart) - moonHeight = mHour - fadeInStart; - else if (mHour <= fadeOutFinish) - moonHeight = mHour + fadeOutFinish; - else - moonHeight = 0; - - moonHeight /= (24.f - (fadeInStart - fadeOutFinish)); - - if (moonHeight != 0) - { - int facing = (moonHeight <= 1) ? 1 : -1; - Vector3 masser( - (moonHeight - 1) * facing, - (1 - moonHeight) * facing, - moonHeight); - - Vector3 secunda( - (moonHeight - 1) * facing * 1.25, - (1 - moonHeight) * facing * 0.8, - moonHeight); - - mRendering->getSkyManager()->setMasserDirection(masser); - mRendering->getSkyManager()->setSecundaDirection(secunda); - mRendering->getSkyManager()->masserEnable(); - mRendering->getSkyManager()->secundaEnable(); - - float angle = (1-moonHeight) * 90.f * facing; - float masserHourFade = calculateHourFade("Masser"); - float secundaHourFade = calculateHourFade("Secunda"); - float masserAngleFade = calculateAngleFade("Masser", angle); - float secundaAngleFade = calculateAngleFade("Secunda", angle); - - masserAngleFade *= masserHourFade; - secundaAngleFade *= secundaHourFade; - - mRendering->getSkyManager()->setMasserFade(masserAngleFade); - mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); - } - else - { - mRendering->getSkyManager()->masserDisable(); - mRendering->getSkyManager()->secundaDisable(); - } - - if (mCurrentWeather == "thunderstorm" && mNextWeather == "" && exterior) - { - if (mThunderFlash > 0) - { - // play the sound after a delay - mThunderSoundDelay -= duration; - if (mThunderSoundDelay <= 0) - { - // pick a random sound - int sound = rand() % 4; - std::string soundname; - if (sound == 0) soundname = mThunderSoundID0; - else if (sound == 1) soundname = mThunderSoundID1; - else if (sound == 2) soundname = mThunderSoundID2; - else if (sound == 3) soundname = mThunderSoundID3; - MWBase::Environment::get().getSoundManager()->playSound(soundname, 1.0, 1.0); - mThunderSoundDelay = 1000; - } - - mThunderFlash -= duration; - if (mThunderFlash > 0) - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - else - { - srand(time(NULL)); - mThunderChanceNeeded = rand() % 100; - mThunderChance = 0; - mRendering->getSkyManager()->setLightningStrength( 0.f ); - } - } - else - { - // no thunder active - mThunderChance += duration*4; // chance increases by 4 percent every second - if (mThunderChance >= mThunderChanceNeeded) - { - mThunderFlash = mThunderThreshold; - - mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); - - mThunderSoundDelay = 0.25; - } - } - } - else - mRendering->getSkyManager()->setLightningStrength(0.f); - - mRendering->setAmbientColour(result.mAmbientColor); - mRendering->sunEnable(false); - mRendering->setSunColour(result.mSunColor); - - mRendering->getSkyManager()->setWeather(result); - } - else + const bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); + if (!exterior) { mRendering->sunDisable(false); mRendering->skyDisable(); mRendering->getSkyManager()->setLightningStrength(0.f); + stopSounds(true); + return; } - // play sounds - std::string ambientSnd = (mNextWeather == "" ? mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID : ""); - if (!exterior) ambientSnd = ""; - if (ambientSnd != "") + // Exterior + std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); + + if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { - if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) + mCurrentRegion = regionstr; + mWeatherUpdateTime = mHoursBetweenWeatherChanges * 3600; + + std::string weatherType = "clear"; + + if (mRegionOverrides.find(regionstr) != mRegionOverrides.end()) + weatherType = mRegionOverrides[regionstr]; + else + { + // get weather probabilities for the current region + const ESM::Region *region = + MWBase::Environment::get().getWorld()->getStore().get().search (regionstr); + + if (region != 0) + { + weatherType = nextWeather(region); + } + } + + setWeather(weatherType, false); + } + + if (mNextWeather != "") + { + mRemainingTransitionTime -= timePassed; + if (mRemainingTransitionTime < 0) + { + mCurrentWeather = mNextWeather; + mNextWeather = ""; + } + } + + if (mNextWeather != "") + transition(1 - (mRemainingTransitionTime / (mWeatherSettings[mCurrentWeather].mTransitionDelta * 24.f * 3600))); + else + setResult(mCurrentWeather); + + mWindSpeed = mResult.mWindSpeed; + + mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); + + // disable sun during night + if (mHour >= mNightStart || mHour <= mSunriseTime) + mRendering->getSkyManager()->sunDisable(); + else + mRendering->getSkyManager()->sunEnable(); + + // sun angle + float height; + + //Day duration + float dayDuration = (mNightStart - 1) - mSunriseTime; + + // rise at 6, set at 20 + if (mHour >= mSunriseTime && mHour <= mNightStart) + height = 1 - std::abs(((mHour - dayDuration) / 7.f)); + else if (mHour > mNightStart) + height = (mHour - mNightStart) / 4.f; + else //if (mHour > 0 && mHour < 6) + height = 1 - (mHour / mSunriseTime); + + int facing = (mHour > 13.f) ? 1 : -1; + + Vector3 final( + (height - 1) * facing, + (height - 1) * facing, + height); + mRendering->setSunDirection(final); + + /* + * TODO: import separated fadeInStart/Finish, fadeOutStart/Finish + * for masser and secunda + */ + + float fadeOutFinish=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Finish"); + float fadeInStart=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); + + //moon calculations + float moonHeight; + if (mHour >= fadeInStart) + moonHeight = mHour - fadeInStart; + else if (mHour <= fadeOutFinish) + moonHeight = mHour + fadeOutFinish; + else + moonHeight = 0; + + moonHeight /= (24.f - (fadeInStart - fadeOutFinish)); + + if (moonHeight != 0) + { + int facing = (moonHeight <= 1) ? 1 : -1; + Vector3 masser( + (moonHeight - 1) * facing, + (1 - moonHeight) * facing, + moonHeight); + + Vector3 secunda( + (moonHeight - 1) * facing * 1.25, + (1 - moonHeight) * facing * 0.8, + moonHeight); + + mRendering->getSkyManager()->setMasserDirection(masser); + mRendering->getSkyManager()->setSecundaDirection(secunda); + mRendering->getSkyManager()->masserEnable(); + mRendering->getSkyManager()->secundaEnable(); + + float angle = (1-moonHeight) * 90.f * facing; + float masserHourFade = calculateHourFade("Masser"); + float secundaHourFade = calculateHourFade("Secunda"); + float masserAngleFade = calculateAngleFade("Masser", angle); + float secundaAngleFade = calculateAngleFade("Secunda", angle); + + masserAngleFade *= masserHourFade; + secundaAngleFade *= secundaHourFade; + + mRendering->getSkyManager()->setMasserFade(masserAngleFade); + mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + } + else + { + mRendering->getSkyManager()->masserDisable(); + mRendering->getSkyManager()->secundaDisable(); + } + + if (mCurrentWeather == "thunderstorm" && mNextWeather == "") + { + if (mThunderFlash > 0) + { + // play the sound after a delay + mThunderSoundDelay -= duration; + if (mThunderSoundDelay <= 0) + { + // pick a random sound + int sound = rand() % 4; + std::string* soundName; + if (sound == 0) soundName = &mThunderSoundID0; + else if (sound == 1) soundName = &mThunderSoundID1; + else if (sound == 2) soundName = &mThunderSoundID2; + else if (sound == 3) soundName = &mThunderSoundID3; + MWBase::Environment::get().getSoundManager()->playSound(*soundName, 1.0, 1.0); + mThunderSoundDelay = 1000; + } + + mThunderFlash -= duration; + if (mThunderFlash > 0) + mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + else + { + mThunderChanceNeeded = rand() % 100; + mThunderChance = 0; + mRendering->getSkyManager()->setLightningStrength( 0.f ); + } + } + else + { + // no thunder active + mThunderChance += duration*4; // chance increases by 4 percent every second + if (mThunderChance >= mThunderChanceNeeded) + { + mThunderFlash = mThunderThreshold; + + mRendering->getSkyManager()->setLightningStrength( mThunderFlash / mThunderThreshold ); + + mThunderSoundDelay = 0.25; + } + } + } + else + mRendering->getSkyManager()->setLightningStrength(0.f); + + mRendering->setAmbientColour(mResult.mAmbientColor); + mRendering->sunEnable(false); + mRendering->setSunColour(mResult.mSunColor); + + mRendering->getSkyManager()->setWeather(mResult); + + + // Play sounds + if (mNextWeather == "") + { + std::string ambientSnd = mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID; + if (!ambientSnd.empty() && std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), ambientSnd) == mSoundsPlaying.end()) { mSoundsPlaying.push_back(ambientSnd); MWBase::Environment::get().getSoundManager()->playSound(ambientSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop); } - } - std::string rainSnd = (mNextWeather == "" ? mWeatherSettings[mCurrentWeather].mRainLoopSoundID : ""); - if (!exterior) rainSnd = ""; - if (rainSnd != "") - { - if (std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) + std::string rainSnd = mWeatherSettings[mCurrentWeather].mRainLoopSoundID; + if (!rainSnd.empty() && std::find(mSoundsPlaying.begin(), mSoundsPlaying.end(), rainSnd) == mSoundsPlaying.end()) { mSoundsPlaying.push_back(rainSnd); MWBase::Environment::get().getSoundManager()->playSound(rainSnd, 1.0, 1.0, MWBase::SoundManager::Play_Loop); } } - // stop sounds - std::vector::iterator it=mSoundsPlaying.begin(); + stopSounds(false); +} + +void WeatherManager::stopSounds(bool stopAll) +{ + std::vector::iterator it = mSoundsPlaying.begin(); while (it!=mSoundsPlaying.end()) { - if ( *it != ambientSnd && *it != rainSnd) + if (stopAll || \ + !((*it == mWeatherSettings[mCurrentWeather].mAmbientLoopSoundID) || \ + (*it == mWeatherSettings[mCurrentWeather].mRainLoopSoundID))) { MWBase::Environment::get().getSoundManager()->stopSound(*it); it = mSoundsPlaying.erase(it); @@ -591,6 +549,62 @@ void WeatherManager::update(float duration) } } +Ogre::String WeatherManager::nextWeather(const ESM::Region* region) const +{ + /* + * All probabilities must add to 100 (responsibility of the user). + * If chances A and B has values 30 and 70 then by generating + * 100 numbers 1..100, 30% will be lesser or equal 30 and + * 70% will be greater than 30 (in theory). + */ + const int probability[] = { + region->mData.mClear, + region->mData.mCloudy, + region->mData.mFoggy, + region->mData.mOvercast, + region->mData.mRain, + region->mData.mThunder, + region->mData.mAsh, + region->mData.mBlight, + region->mData.mA, + region->mData.mB + }; // 10 elements + + int chance = (rand() % 100) + 1; // 1..100 + int sum = 0; + int i = 0; + for (; i < 10; ++i) + { + sum += probability[i]; + if (chance < sum) + break; + } + + switch (i) + { + case 1: + return "cloudy"; + case 2: + return "foggy"; + case 3: + return "overcast"; + case 4: + return "rain"; + case 5: + return "thunderstorm"; + case 6: + return "ashstorm"; + case 7: + return "blight"; + case 8: + return "snow"; + case 9: + return "blizzard"; + default: // case 0 + return "clear"; + } +} + void WeatherManager::setHour(const float hour) { mHour = hour; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 081bd7f87..1a787aae8 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -4,6 +4,11 @@ #include #include +namespace ESM +{ + struct Region; +} + namespace MWRender { class RenderingManager; @@ -129,6 +134,8 @@ namespace MWWorld */ void update(float duration); + void stopSounds(bool stopAll); + void setHour(const float hour); float getWindSpeed() const; @@ -171,13 +178,16 @@ namespace MWWorld double mTimePassed; // time passed since last update - WeatherResult transition(const float factor); - WeatherResult getResult(const Ogre::String& weather); + void transition(const float factor); + void setResult(const Ogre::String& weatherType); float calculateHourFade (const std::string& moonName) const; float calculateAngleFade (const std::string& moonName, float angle) const; - void setWeather(const Ogre::String& weather, bool instant=false); + void setWeather(const Ogre::String& weatherType, bool instant=false); + Ogre::String nextWeather(const ESM::Region* region) const; + WeatherResult mResult; + float mSunriseTime; float mSunsetTime; float mSunriseDuration; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8b76efdae..0a1e0ccdc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1724,4 +1724,45 @@ namespace MWWorld } } } + + struct ListHandlesFunctor + { + std::vector mHandles; + + bool operator() (ESM::CellRef& ref, RefData& data) + { + Ogre::SceneNode* handle = data.getBaseNode(); + if (handle) + mHandles.push_back(handle->getName()); + return true; + } + }; + + void World::getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out) + { + const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); + for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) + { + ListHandlesFunctor functor; + (*cellIt)->forEach(functor); + + for (std::vector::iterator it = functor.mHandles.begin(); it != functor.mHandles.end(); ++it) + if (Misc::StringUtils::ciEqual(searchPtrViaHandle(*it).mCellRef->mOwner, npc.getCellRef().mRefID)) + out.push_back(searchPtrViaHandle(*it)); + } + } + + void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) + { + OEngine::Physic::PhysicActor *physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); + + if (enable) + { + physicActor->enableCollisionBody(); + } + else + { + physicActor->disableCollisionBody(); + } + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1baf3d4ba..5cf3a24bf 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -391,6 +391,10 @@ namespace MWWorld virtual void getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector& out); ///< get all containers in active cells owned by this Npc + virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector& out); + ///< get all items in active cells owned by this Npc + + virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); diff --git a/cmake/FindOIS.cmake b/cmake/FindOIS.cmake deleted file mode 100644 index e0278d8a2..000000000 --- a/cmake/FindOIS.cmake +++ /dev/null @@ -1,87 +0,0 @@ -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- - -# - Try to find OIS -# Once done, this will define -# -# OIS_FOUND - system has OIS -# OIS_INCLUDE_DIRS - the OIS include directories -# OIS_LIBRARIES - link these to use OIS -# OIS_BINARY_REL / OIS_BINARY_DBG - DLL names (windows only) - -include(FindPkgMacros) -findpkg_begin(OIS) - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(OIS_HOME) -getenv_path(OGRE_SDK) -getenv_path(OGRE_HOME) -getenv_path(OGRE_SOURCE) -getenv_path(OGRE_DEPENDENCIES_DIR) - -# construct search paths -set(OIS_PREFIX_PATH ${OIS_HOME} ${ENV_OIS_HOME} - ${OGRE_DEPENDENCIES_DIR} ${ENV_OGRE_DEPENDENCIES_DIR} - ${OGRE_SOURCE}/iPhoneDependencies ${ENV_OGRE_SOURCE}/iPhoneDependencies - ${OGRE_SOURCE}/Dependencies ${ENV_OGRE_SOURCE}/Dependencies - ${OGRE_SDK} ${ENV_OGRE_SDK} - ${OGRE_HOME} ${ENV_OGRE_HOME}) -create_search_paths(OIS) -# redo search if prefix path changed -clear_if_changed(OIS_PREFIX_PATH - OIS_LIBRARY_FWK - OIS_LIBRARY_REL - OIS_LIBRARY_DBG - OIS_INCLUDE_DIR -) - -set(OIS_LIBRARY_NAMES OIS) -get_debug_names(OIS_LIBRARY_NAMES) - -use_pkgconfig(OIS_PKGC OIS) - -# For OIS, prefer static library over framework (important when referencing OIS source build) -set(CMAKE_FIND_FRAMEWORK "LAST") - -findpkg_framework(OIS) -if (OIS_HOME) - # OIS uses the 'includes' path for its headers in the source release, not 'include' - set(OIS_INC_SEARCH_PATH ${OIS_INC_SEARCH_PATH} ${OIS_HOME}/includes) -endif() -if (APPLE AND OIS_HOME) - # OIS source build on Mac stores libs in a different location - # Also this is for static build - set(OIS_LIB_SEARCH_PATH ${OIS_LIB_SEARCH_PATH} ${OIS_HOME}/Mac/XCode-2.2/build) -endif() -find_path(OIS_INCLUDE_DIR NAMES OIS.h HINTS ${OIS_INC_SEARCH_PATH} ${OIS_PKGC_INCLUDE_DIRS} PATH_SUFFIXES OIS) -find_library(OIS_LIBRARY_REL NAMES ${OIS_LIBRARY_NAMES} HINTS ${OIS_LIB_SEARCH_PATH} ${OIS_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) -find_library(OIS_LIBRARY_DBG NAMES ${OIS_LIBRARY_NAMES_DBG} HINTS ${OIS_LIB_SEARCH_PATH} ${OIS_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) -make_library_set(OIS_LIBRARY) - -if (WIN32) - set(OIS_BIN_SEARCH_PATH ${OIS_HOME}/dll ${ENV_OIS_HOME}/dll - ${OGRE_DEPENDENCIES_DIR}/bin ${ENV_OGRE_DEPENDENCIES_DIR}/bin - ${OGRE_SOURCE}/Dependencies/bin ${ENV_OGRE_SOURCE}/Dependencies/bin - ${OGRE_SDK}/bin ${ENV_OGRE_SDK}/bin - ${OGRE_HOME}/bin ${ENV_OGRE_HOME}/bin) - find_file(OIS_BINARY_REL NAMES "OIS.dll" HINTS ${OIS_BIN_SEARCH_PATH} - PATH_SUFFIXES "" release relwithdebinfo minsizerel) - find_file(OIS_BINARY_DBG NAMES "OIS_d.dll" HINTS ${OIS_BIN_SEARCH_PATH} - PATH_SUFFIXES "" debug ) -endif() -mark_as_advanced(OIS_BINARY_REL OIS_BINARY_DBG) - - -findpkg_finish(OIS) - -# add parent of OIS folder to support OIS/OIS.h -add_parent_dir(OIS_INCLUDE_DIRS OIS_INCLUDE_DIR) - -# Reset framework finding -set(CMAKE_FIND_FRAMEWORK "FIRST") diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake new file mode 100644 index 000000000..70e607a89 --- /dev/null +++ b/cmake/FindSDL2.cmake @@ -0,0 +1,193 @@ +# 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) + + 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") + # 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) + +IF(SDL2_STATIC) + if (UNIX AND NOT APPLE) + EXECUTE_PROCESS(COMMAND sdl2-config --static-libs OUTPUT_VARIABLE SDL2_LINK_FLAGS) + STRING(REGEX REPLACE "(\r?\n)+$" "" SDL2_LINK_FLAGS "${SDL2_LINK_FLAGS}") + SET(SDL2_LIBRARY ${SDL2_LINK_FLAGS}) + ENDIF() +ENDIF(SDL2_STATIC) diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index 9f2e470b2..02a6766b0 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include @@ -12,6 +11,8 @@ #include "datafilesmodel.hpp" +#include + DataFilesModel::DataFilesModel(QObject *parent) : QAbstractTableModel(parent) { diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index 9056e792d..765f1cebf 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -3,6 +3,8 @@ #ifdef _WIN32 #include +#elif defined HAVE_UNORDERED_MAP +#include #else #include #endif @@ -48,7 +50,11 @@ struct ConfigurationManager typedef Files::FixedPath<> FixedPathType; typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const; - typedef std::tr1::unordered_map TokensMappingContainer; + #if defined HAVE_UNORDERED_MAP + typedef std::unordered_map TokensMappingContainer; + #else + typedef std::tr1::unordered_map TokensMappingContainer; + #endif void loadConfig(const boost::filesystem::path& path, boost::program_options::variables_map& variables, diff --git a/components/to_utf8/gen_iconv.cpp b/components/to_utf8/gen_iconv.cpp index dea68c1fa..8198b305d 100644 --- a/components/to_utf8/gen_iconv.cpp +++ b/components/to_utf8/gen_iconv.cpp @@ -46,7 +46,7 @@ void writeMissing(bool last) int write_table(const std::string &charset, const std::string &tableName) { // Write table header - cout << "static char " << tableName << "[] =\n{\n"; + cout << "static signed char " << tableName << "[] =\n{\n"; // Open conversion system iconv_t cd = iconv_open ("UTF-8", charset.c_str()); @@ -106,6 +106,8 @@ int main() "\n"; write_table("WINDOWS-1252", "windows_1252"); + write_table("CP437", "cp437"); + // Close namespace cout << "\n}\n\n"; diff --git a/components/to_utf8/tables_gen.hpp b/components/to_utf8/tables_gen.hpp index a1d4b6d80..14e66eac1 100644 --- a/components/to_utf8/tables_gen.hpp +++ b/components/to_utf8/tables_gen.hpp @@ -790,6 +790,265 @@ static signed char windows_1252[] = 2, -61, -66, 0, 0, 0, 2, -61, -65, 0, 0, 0 }; +static signed char cp437[] = +{ + 1, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 0, + 1, 3, 0, 0, 0, 0, + 1, 4, 0, 0, 0, 0, + 1, 5, 0, 0, 0, 0, + 1, 6, 0, 0, 0, 0, + 1, 7, 0, 0, 0, 0, + 1, 8, 0, 0, 0, 0, + 1, 9, 0, 0, 0, 0, + 1, 10, 0, 0, 0, 0, + 1, 11, 0, 0, 0, 0, + 1, 12, 0, 0, 0, 0, + 1, 13, 0, 0, 0, 0, + 1, 14, 0, 0, 0, 0, + 1, 15, 0, 0, 0, 0, + 1, 16, 0, 0, 0, 0, + 1, 17, 0, 0, 0, 0, + 1, 18, 0, 0, 0, 0, + 1, 19, 0, 0, 0, 0, + 1, 20, 0, 0, 0, 0, + 1, 21, 0, 0, 0, 0, + 1, 22, 0, 0, 0, 0, + 1, 23, 0, 0, 0, 0, + 1, 24, 0, 0, 0, 0, + 1, 25, 0, 0, 0, 0, + 1, 26, 0, 0, 0, 0, + 1, 27, 0, 0, 0, 0, + 1, 28, 0, 0, 0, 0, + 1, 29, 0, 0, 0, 0, + 1, 30, 0, 0, 0, 0, + 1, 31, 0, 0, 0, 0, + 1, 32, 0, 0, 0, 0, + 1, 33, 0, 0, 0, 0, + 1, 34, 0, 0, 0, 0, + 1, 35, 0, 0, 0, 0, + 1, 36, 0, 0, 0, 0, + 1, 37, 0, 0, 0, 0, + 1, 38, 0, 0, 0, 0, + 1, 39, 0, 0, 0, 0, + 1, 40, 0, 0, 0, 0, + 1, 41, 0, 0, 0, 0, + 1, 42, 0, 0, 0, 0, + 1, 43, 0, 0, 0, 0, + 1, 44, 0, 0, 0, 0, + 1, 45, 0, 0, 0, 0, + 1, 46, 0, 0, 0, 0, + 1, 47, 0, 0, 0, 0, + 1, 48, 0, 0, 0, 0, + 1, 49, 0, 0, 0, 0, + 1, 50, 0, 0, 0, 0, + 1, 51, 0, 0, 0, 0, + 1, 52, 0, 0, 0, 0, + 1, 53, 0, 0, 0, 0, + 1, 54, 0, 0, 0, 0, + 1, 55, 0, 0, 0, 0, + 1, 56, 0, 0, 0, 0, + 1, 57, 0, 0, 0, 0, + 1, 58, 0, 0, 0, 0, + 1, 59, 0, 0, 0, 0, + 1, 60, 0, 0, 0, 0, + 1, 61, 0, 0, 0, 0, + 1, 62, 0, 0, 0, 0, + 1, 63, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 1, 65, 0, 0, 0, 0, + 1, 66, 0, 0, 0, 0, + 1, 67, 0, 0, 0, 0, + 1, 68, 0, 0, 0, 0, + 1, 69, 0, 0, 0, 0, + 1, 70, 0, 0, 0, 0, + 1, 71, 0, 0, 0, 0, + 1, 72, 0, 0, 0, 0, + 1, 73, 0, 0, 0, 0, + 1, 74, 0, 0, 0, 0, + 1, 75, 0, 0, 0, 0, + 1, 76, 0, 0, 0, 0, + 1, 77, 0, 0, 0, 0, + 1, 78, 0, 0, 0, 0, + 1, 79, 0, 0, 0, 0, + 1, 80, 0, 0, 0, 0, + 1, 81, 0, 0, 0, 0, + 1, 82, 0, 0, 0, 0, + 1, 83, 0, 0, 0, 0, + 1, 84, 0, 0, 0, 0, + 1, 85, 0, 0, 0, 0, + 1, 86, 0, 0, 0, 0, + 1, 87, 0, 0, 0, 0, + 1, 88, 0, 0, 0, 0, + 1, 89, 0, 0, 0, 0, + 1, 90, 0, 0, 0, 0, + 1, 91, 0, 0, 0, 0, + 1, 92, 0, 0, 0, 0, + 1, 93, 0, 0, 0, 0, + 1, 94, 0, 0, 0, 0, + 1, 95, 0, 0, 0, 0, + 1, 96, 0, 0, 0, 0, + 1, 97, 0, 0, 0, 0, + 1, 98, 0, 0, 0, 0, + 1, 99, 0, 0, 0, 0, + 1, 100, 0, 0, 0, 0, + 1, 101, 0, 0, 0, 0, + 1, 102, 0, 0, 0, 0, + 1, 103, 0, 0, 0, 0, + 1, 104, 0, 0, 0, 0, + 1, 105, 0, 0, 0, 0, + 1, 106, 0, 0, 0, 0, + 1, 107, 0, 0, 0, 0, + 1, 108, 0, 0, 0, 0, + 1, 109, 0, 0, 0, 0, + 1, 110, 0, 0, 0, 0, + 1, 111, 0, 0, 0, 0, + 1, 112, 0, 0, 0, 0, + 1, 113, 0, 0, 0, 0, + 1, 114, 0, 0, 0, 0, + 1, 115, 0, 0, 0, 0, + 1, 116, 0, 0, 0, 0, + 1, 117, 0, 0, 0, 0, + 1, 118, 0, 0, 0, 0, + 1, 119, 0, 0, 0, 0, + 1, 120, 0, 0, 0, 0, + 1, 121, 0, 0, 0, 0, + 1, 122, 0, 0, 0, 0, + 1, 123, 0, 0, 0, 0, + 1, 124, 0, 0, 0, 0, + 1, 125, 0, 0, 0, 0, + 1, 126, 0, 0, 0, 0, + 1, 127, 0, 0, 0, 0, + 2, -61, -121, 0, 0, 0, + 2, -61, -68, 0, 0, 0, + 2, -61, -87, 0, 0, 0, + 2, -61, -94, 0, 0, 0, + 2, -61, -92, 0, 0, 0, + 2, -61, -96, 0, 0, 0, + 2, -61, -91, 0, 0, 0, + 2, -61, -89, 0, 0, 0, + 2, -61, -86, 0, 0, 0, + 2, -61, -85, 0, 0, 0, + 2, -61, -88, 0, 0, 0, + 2, -61, -81, 0, 0, 0, + 2, -61, -82, 0, 0, 0, + 2, -61, -84, 0, 0, 0, + 2, -61, -124, 0, 0, 0, + 2, -61, -123, 0, 0, 0, + 2, -61, -119, 0, 0, 0, + 2, -61, -90, 0, 0, 0, + 2, -61, -122, 0, 0, 0, + 2, -61, -76, 0, 0, 0, + 2, -61, -74, 0, 0, 0, + 2, -61, -78, 0, 0, 0, + 2, -61, -69, 0, 0, 0, + 2, -61, -71, 0, 0, 0, + 2, -61, -65, 0, 0, 0, + 2, -61, -106, 0, 0, 0, + 2, -61, -100, 0, 0, 0, + 2, -62, -94, 0, 0, 0, + 2, -62, -93, 0, 0, 0, + 2, -62, -91, 0, 0, 0, + 3, -30, -126, -89, 0, 0, + 2, -58, -110, 0, 0, 0, + 2, -61, -95, 0, 0, 0, + 2, -61, -83, 0, 0, 0, + 2, -61, -77, 0, 0, 0, + 2, -61, -70, 0, 0, 0, + 2, -61, -79, 0, 0, 0, + 2, -61, -111, 0, 0, 0, + 2, -62, -86, 0, 0, 0, + 2, -62, -70, 0, 0, 0, + 2, -62, -65, 0, 0, 0, + 3, -30, -116, -112, 0, 0, + 2, -62, -84, 0, 0, 0, + 2, -62, -67, 0, 0, 0, + 2, -62, -68, 0, 0, 0, + 2, -62, -95, 0, 0, 0, + 2, -62, -85, 0, 0, 0, + 2, -62, -69, 0, 0, 0, + 3, -30, -106, -111, 0, 0, + 3, -30, -106, -110, 0, 0, + 3, -30, -106, -109, 0, 0, + 3, -30, -108, -126, 0, 0, + 3, -30, -108, -92, 0, 0, + 3, -30, -107, -95, 0, 0, + 3, -30, -107, -94, 0, 0, + 3, -30, -107, -106, 0, 0, + 3, -30, -107, -107, 0, 0, + 3, -30, -107, -93, 0, 0, + 3, -30, -107, -111, 0, 0, + 3, -30, -107, -105, 0, 0, + 3, -30, -107, -99, 0, 0, + 3, -30, -107, -100, 0, 0, + 3, -30, -107, -101, 0, 0, + 3, -30, -108, -112, 0, 0, + 3, -30, -108, -108, 0, 0, + 3, -30, -108, -76, 0, 0, + 3, -30, -108, -84, 0, 0, + 3, -30, -108, -100, 0, 0, + 3, -30, -108, -128, 0, 0, + 3, -30, -108, -68, 0, 0, + 3, -30, -107, -98, 0, 0, + 3, -30, -107, -97, 0, 0, + 3, -30, -107, -102, 0, 0, + 3, -30, -107, -108, 0, 0, + 3, -30, -107, -87, 0, 0, + 3, -30, -107, -90, 0, 0, + 3, -30, -107, -96, 0, 0, + 3, -30, -107, -112, 0, 0, + 3, -30, -107, -84, 0, 0, + 3, -30, -107, -89, 0, 0, + 3, -30, -107, -88, 0, 0, + 3, -30, -107, -92, 0, 0, + 3, -30, -107, -91, 0, 0, + 3, -30, -107, -103, 0, 0, + 3, -30, -107, -104, 0, 0, + 3, -30, -107, -110, 0, 0, + 3, -30, -107, -109, 0, 0, + 3, -30, -107, -85, 0, 0, + 3, -30, -107, -86, 0, 0, + 3, -30, -108, -104, 0, 0, + 3, -30, -108, -116, 0, 0, + 3, -30, -106, -120, 0, 0, + 3, -30, -106, -124, 0, 0, + 3, -30, -106, -116, 0, 0, + 3, -30, -106, -112, 0, 0, + 3, -30, -106, -128, 0, 0, + 2, -50, -79, 0, 0, 0, + 2, -61, -97, 0, 0, 0, + 2, -50, -109, 0, 0, 0, + 2, -49, -128, 0, 0, 0, + 2, -50, -93, 0, 0, 0, + 2, -49, -125, 0, 0, 0, + 2, -62, -75, 0, 0, 0, + 2, -49, -124, 0, 0, 0, + 2, -50, -90, 0, 0, 0, + 2, -50, -104, 0, 0, 0, + 2, -50, -87, 0, 0, 0, + 2, -50, -76, 0, 0, 0, + 3, -30, -120, -98, 0, 0, + 2, -49, -122, 0, 0, 0, + 2, -50, -75, 0, 0, 0, + 3, -30, -120, -87, 0, 0, + 3, -30, -119, -95, 0, 0, + 2, -62, -79, 0, 0, 0, + 3, -30, -119, -91, 0, 0, + 3, -30, -119, -92, 0, 0, + 3, -30, -116, -96, 0, 0, + 3, -30, -116, -95, 0, 0, + 2, -61, -73, 0, 0, 0, + 3, -30, -119, -120, 0, 0, + 2, -62, -80, 0, 0, 0, + 3, -30, -120, -103, 0, 0, + 2, -62, -73, 0, 0, 0, + 3, -30, -120, -102, 0, 0, + 3, -30, -127, -65, 0, 0, + 2, -62, -78, 0, 0, 0, + 3, -30, -106, -96, 0, 0, + 2, -62, -96, 0, 0, 0 +}; } diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 1de15d79c..59a9aff80 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -63,6 +63,12 @@ Utf8Encoder::Utf8Encoder(const FromType sourceEncoding): translationArray = ToUTF8::windows_1251; break; } + case ToUTF8::CP437: + { + translationArray = ToUTF8::cp437; + break; + } + default: { assert(0); diff --git a/components/to_utf8/to_utf8.hpp b/components/to_utf8/to_utf8.hpp index 839aa36aa..3f20a51f8 100644 --- a/components/to_utf8/to_utf8.hpp +++ b/components/to_utf8/to_utf8.hpp @@ -12,8 +12,9 @@ namespace ToUTF8 { WINDOWS_1250, // Central ane Eastern European languages WINDOWS_1251, // Cyrillic languages - WINDOWS_1252 // Used by English version of Morrowind (and + WINDOWS_1252, // Used by English version of Morrowind (and // probably others) + CP437 // Used for fonts (*.fnt) if data files encoding is 1252. Otherwise, uses the same encoding as the data files. }; FromType calculateEncoding(const std::string& encodingName); diff --git a/credits.txt b/credits.txt index 390a2d721..30cfc7e57 100644 --- a/credits.txt +++ b/credits.txt @@ -12,6 +12,7 @@ Marc Zinnschlag (Zini) - Lead Programmer/Project Manager Adam Hogan (aurix) Aleksandar Jovanov +Alex McKibben (WeirdSexy) Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) @@ -21,6 +22,7 @@ BrotherBrick Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) Cris Mihalache (Mirceam) +darkf Douglas Diniz (Dgdiniz) Douglas Mencken (dougmencken) Edmondo Tommasina (edmondo) @@ -32,6 +34,7 @@ Jacob Essex (Yacoby) Jannik Heller (scrawl) Jason Hooks (jhooks) Joel Graff (graffy) +John Blomberg (fstp) Jordan Milne Julien Voisin (jvoisin/ap0) Karl-Felix Glatzer (k1ll) @@ -77,7 +80,7 @@ Julien Voisin (jvoisin/ap0) - French News Writer Mickey Lyle (raevol) - Release Manager Pithorn - Chinese News Writer sir_herrbatka - English/Polish News Writer -WeirdSexy - Podcaster +Alex McKibben (WeirdSexy) - Podcaster Website: diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 1702c853e..cdf8fbfe2 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..f42f9c0b5 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 "../sdl4ogre/events.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 SFO::MouseListener, + public SFO::KeyListener, + public SFO::JoyListener { 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 SFO::MouseMotionEvent &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..52eb894ed 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 SFO::MouseMotionEvent& 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..52daea3f4 100644 --- a/extern/oics/ICSPrerequisites.h +++ b/extern/oics/ICSPrerequisites.h @@ -39,11 +39,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tinyxml.h" -#include -#include -#include -#include -#include +#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 @@ -65,8 +64,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/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt new file mode 100644 index 000000000..493d1ce47 --- /dev/null +++ b/extern/sdl4ogre/CMakeLists.txt @@ -0,0 +1,20 @@ +set(SDL4OGRE_LIBRARY "sdl4ogre") + +# Sources + +set(SDL4OGRE_SOURCE_FILES + sdlinputwrapper.cpp + sdlcursormanager.cpp +) + +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}) + + +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..3cffa143d --- /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/sdl4ogre/cursormanager.hpp b/extern/sdl4ogre/cursormanager.hpp new file mode 100644 index 000000000..1f52eca73 --- /dev/null +++ b/extern/sdl4ogre/cursormanager.hpp @@ -0,0 +1,35 @@ +#ifndef _SDL4OGRE_CURSOR_MANAGER_H +#define _SDL4OGRE_CURSOR_MANAGER_H + +#include +#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, int rotDegrees, 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/events.h b/extern/sdl4ogre/events.h new file mode 100644 index 000000000..13f8b3101 --- /dev/null +++ b/extern/sdl4ogre/events.h @@ -0,0 +1,76 @@ +#ifndef _SFO_EVENTS_H +#define _SFO_EVENTS_H + +#include + + +//////////// +// Events // +//////////// + +namespace SFO { + +/** Extended mouse event struct where we treat the wheel like an axis, like everyone expects */ +struct MouseMotionEvent : SDL_MouseMotionEvent { + + Sint32 zrel; + Sint32 z; +}; + + +/////////////// +// Listeners // +/////////////// + +class MouseListener +{ +public: + 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 KeyListener +{ +public: + virtual ~KeyListener() {} + virtual void textInput (const SDL_TextInputEvent& arg) {} + virtual bool keyPressed(const SDL_KeyboardEvent &arg) = 0; + virtual bool keyReleased(const SDL_KeyboardEvent &arg) = 0; +}; + +class JoyListener +{ +public: + virtual ~JoyListener() {} + /** @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;} +}; + +class WindowListener +{ +public: + virtual ~WindowListener() {} + + /** @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 diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp new file mode 100644 index 000000000..d14a9ffa0 --- /dev/null +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -0,0 +1,177 @@ +#include "sdlcursormanager.hpp" + +#include +#include + +#include + +namespace SFO +{ + + SDLCursorManager::SDLCursorManager() : + 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 + { + 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 && mCursorVisible) + { + SDL_SetCursor(mCursorMap.find(name)->second); + _setCursorVisible(mCursorVisible); + } + } + + void SDLCursorManager::_setCursorVisible(bool visible) + { + if(!mEnabled) + return; + + 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, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + _createCursorFromResource(name, rotDegrees, 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, int rotDegrees, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + if (mCursorMap.find(name) != mCursorMap.end()) + return; + + std::string tempName = tex->getName() + "_rotated"; + + // we use a render target to uncompress the DDS texture + // just blitting doesn't seem to work on D3D9 + OEngine::Render::ImageRotate::rotate(tex->getName(), tempName, -rotDegrees); + + Ogre::TexturePtr resultTexture = Ogre::TextureManager::getSingleton().getByName(tempName); + + // now blit to memory + Ogre::Image destImage; + resultTexture->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..3dae42f42 --- /dev/null +++ b/extern/sdl4ogre/sdlcursormanager.hpp @@ -0,0 +1,42 @@ +#ifndef _SDL4OGRE_CURSORMANAGER_H +#define _SDL4OGRE_CURSORMANAGER_H + +#include + +#include "cursormanager.hpp" +#include + +namespace SFO +{ + class SDLCursorManager : + public CursorManager + { + public: + SDLCursorManager(); + virtual ~SDLCursorManager(); + + virtual void setEnabled(bool enabled); + + virtual bool cursorChanged(const std::string &name); + virtual void receiveCursorInfo(const std::string &name, int rotDegrees, 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, int rotDegrees, 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; + }; +} + +#endif diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp new file mode 100644 index 000000000..5c1df52c6 --- /dev/null +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -0,0 +1,348 @@ +#include "sdlinputwrapper.hpp" +#include + +#include +#include + +/* +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +# include +# include +# include +#endif +*/ + +namespace SFO +{ + /// \brief General purpose wrapper for OGRE applications around SDL's event + /// queue, mostly used for handling input-related events. + InputWrapper::InputWrapper(SDL_Window* window, Ogre::RenderWindow* ogreWindow) : + mSDLWindow(window), + mOgreWindow(ogreWindow), + mOwnWindow(false), + mWarpCompensate(false), + mMouseRelative(false), + mGrabPointer(false), + mWrapPointer(false), + mMouseZ(0), + mMouseY(0), + mMouseX(0), + mMouseInWindow(true) + { + _setupOISKeys(); + } + + InputWrapper::~InputWrapper() + { + if(mSDLWindow != NULL && mOwnWindow) + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + } + + void InputWrapper::capture() + { + 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: + if (!evt.key.repeat) + mKeyboardListener->keyPressed(evt.key); + break; + case SDL_KEYUP: + if (!evt.key.repeat) + mKeyboardListener->keyReleased(evt.key); + break; + case SDL_TEXTINPUT: + mKeyboardListener->textInput(evt.text); + break; + case SDL_WINDOWEVENT: + handleWindowEvent(evt); + break; + case SDL_QUIT: + Ogre::Root::getSingleton().queueEndRendering(); + break; + default: + std::cerr << "Unhandled SDL event of type " << evt.type << std::endl; + break; + } + } + } + + void InputWrapper::handleWindowEvent(const SDL_Event& evt) + { + switch (evt.window.event) { + case SDL_WINDOWEVENT_ENTER: + mMouseInWindow = true; + break; + case SDL_WINDOWEVENT_LEAVE: + mMouseInWindow = false; + SDL_SetWindowGrab(mSDLWindow, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + break; + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_FOCUS_GAINED: + case SDL_WINDOWEVENT_FOCUS_LOST: + case SDL_WINDOWEVENT_CLOSE: + break; + } + } + + bool InputWrapper::isModifierHeld(int mod) + { + 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); + mWarpCompensate = true; + mWarpX = x; + mWarpY = y; + } + + /// \brief Locks the pointer to the window + void InputWrapper::setGrabPointer(bool grab) + { + mGrabPointer = grab && mMouseInWindow; + SDL_SetWindowGrab(mSDLWindow, grab && mMouseInWindow ? 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 && mMouseInWindow) + return; + + mMouseRelative = relative && mMouseInWindow; + + mWrapPointer = false; + + //eep, wrap the pointer manually if the input driver doesn't support + //relative positioning natively + int success = SDL_SetRelativeMouseMode(relative && mMouseInWindow ? SDL_TRUE : SDL_FALSE); + if(relative && mMouseInWindow && success != 0) + mWrapPointer = true; + + //now remove all mouse events using the old setting from the queue + SDL_PumpEvents(); + SDL_FlushEvent(SDL_MOUSEMOTION); + } + + /// \brief Internal method for ignoring relative motions as a side effect + /// of warpMouse() + 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; + } + + /// \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 + //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; + const int FUDGE_FACTOR_Y = height; + + //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); + } + } + + /// \brief Package mouse and mousewheel motions into a single event + 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 * 120); + 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 + + //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) ); + 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..08b329925 --- /dev/null +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -0,0 +1,74 @@ +#ifndef _SDL4OGRE_SDLINPUTWRAPPER_H +#define _SDL4OGRE_SDLINPUTWRAPPER_H + +#include + +#include +#include + +#include "OISCompat.h" +#include "events.h" + + + +namespace SFO +{ + class InputWrapper + { + public: + InputWrapper(SDL_Window *window, Ogre::RenderWindow* ogreWindow); + ~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: + + void handleWindowEvent(const SDL_Event& evt); + + bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); + void _wrapMousePointer(const SDL_MouseMotionEvent &evt); + MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); + + void _setupOISKeys(); + + SFO::MouseListener* mMouseListener; + SFO::KeyListener* mKeyboardListener; + SFO::WindowListener* mWindowListener; + + typedef boost::unordered_map KeyMap; + KeyMap mKeyMap; + + Uint16 mWarpX; + Uint16 mWarpY; + bool mWarpCompensate; + bool mMouseRelative; + bool mWrapPointer; + bool mGrabPointer; + + Sint32 mMouseZ; + Sint32 mMouseX; + Sint32 mMouseY; + + bool mMouseInWindow; + + SDL_Window* mSDLWindow; + Ogre::RenderWindow* mOgreWindow; + bool mOwnWindow; + }; + +} + +#endif diff --git a/extern/shiny/Docs/Materials.dox b/extern/shiny/Docs/Materials.dox index 91e9be4b3..d08599a04 100644 --- a/extern/shiny/Docs/Materials.dox +++ b/extern/shiny/Docs/Materials.dox @@ -87,6 +87,8 @@ Now, let's get into writing our shader! As you can guess from above, the filename should be 'example.shader'. Make sure to also copy the 'core.h' file to the same location. It is included in shiny's source tree under 'Extra/'. + Important: a newline at the end of the file is required. Many editors do this automatically or can be configured to do so. If there is no newline at the end of the file, and the last line is '#endif', you will get the rather cryptic error message " ill formed preprocessor directive: #endif" from boost::wave. + \code #include "core.h" diff --git a/extern/shiny/Editor/Actions.hpp b/extern/shiny/Editor/Actions.hpp index e5cb6df6a..1bbdbe5a9 100644 --- a/extern/shiny/Editor/Actions.hpp +++ b/extern/shiny/Editor/Actions.hpp @@ -10,7 +10,7 @@ namespace sh { public: virtual void execute() = 0; - virtual ~Action(); + virtual ~Action() {} }; class ActionDeleteMaterial : public Action diff --git a/extern/shiny/Editor/Query.hpp b/extern/shiny/Editor/Query.hpp index 7aec68488..d98c8c9b2 100644 --- a/extern/shiny/Editor/Query.hpp +++ b/extern/shiny/Editor/Query.hpp @@ -15,7 +15,7 @@ class Query public: Query() : mDone(false) {} - virtual ~Query(); + virtual ~Query() {} void execute(); diff --git a/files/materials/core.h b/files/materials/core.h index 3385e5fac..6f8179c08 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -58,11 +58,20 @@ #endif -#if SH_GLSL == 1 +#if SH_GLSL == 1 || SH_GLSLES == 1 #define shFract(val) fract(val) +#if SH_GLSLES == 1 + @version 100 +#else @version 120 +#endif + +#if SH_GLSLES == 1 && SH_FRAGMENT_SHADER +precision mediump int; +precision mediump float; +#endif #define float2 vec2 #define float3 vec3 diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index af695ac6c..1ec1e08cb 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -84,6 +84,7 @@ set(MYGUI_FILES smallbars.png DejaVuLGCSansMono.ttf markers.png + ../launcher/images/openmw.png ) diff --git a/files/mygui/core.skin b/files/mygui/core.skin index e52080fe0..ea3e2debc 100644 --- a/files/mygui/core.skin +++ b/files/mygui/core.skin @@ -2,7 +2,6 @@ - diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index c569abb86..55dbe3218 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -14,7 +14,7 @@ - + diff --git a/files/mygui/openmw_count_window.layout b/files/mygui/openmw_count_window.layout index 5812ec7fd..4e24277af 100644 --- a/files/mygui/openmw_count_window.layout +++ b/files/mygui/openmw_count_window.layout @@ -16,7 +16,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index 46090d000..a314ba312 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -10,7 +10,7 @@ - + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index da21385e2..1f14f6f66 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -45,7 +45,7 @@ - + diff --git a/files/mygui/openmw_edit_effect.layout b/files/mygui/openmw_edit_effect.layout index cad22c064..fa1e58b9d 100644 --- a/files/mygui/openmw_edit_effect.layout +++ b/files/mygui/openmw_edit_effect.layout @@ -31,7 +31,7 @@ - + @@ -39,7 +39,7 @@ - + @@ -56,7 +56,7 @@ - + @@ -72,7 +72,7 @@ - + diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index ef4300326..726bfb281 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -23,56 +23,21 @@ - - - - + + + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index a5065c7ca..d680f80d2 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -120,7 +120,7 @@ - + @@ -150,7 +150,7 @@ - + diff --git a/files/mygui/openmw_map_window_skin.xml b/files/mygui/openmw_map_window_skin.xml index 13f18c6d3..2f5bb4faf 100644 --- a/files/mygui/openmw_map_window_skin.xml +++ b/files/mygui/openmw_map_window_skin.xml @@ -5,7 +5,7 @@ - - + + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index 1b94f0c29..76e22c69f 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -4,12 +4,12 @@ - + - + diff --git a/files/mygui/openmw_settings.xml b/files/mygui/openmw_settings.xml index c63f962fb..37d235968 100644 --- a/files/mygui/openmw_settings.xml +++ b/files/mygui/openmw_settings.xml @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 77d14d0f6..ab91aed78 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -15,8 +15,9 @@ - - + + + @@ -30,8 +31,9 @@ - - + + + @@ -64,36 +66,41 @@ - - + + + - - + + + - - + + + - - + + + - - + + + @@ -114,33 +121,18 @@ - - - - - - - - - - - - - - - - - + - - + + + - + - + @@ -198,8 +190,9 @@ - - + + + @@ -223,16 +216,18 @@ - - + + + - - + + + diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout index 66e0ec22f..eeb7012eb 100644 --- a/files/mygui/openmw_wait_dialog.layout +++ b/files/mygui/openmw_wait_dialog.layout @@ -16,7 +16,7 @@ - + diff --git a/files/opencs.cfg b/files/opencs.cfg new file mode 100644 index 000000000..3faac7c8e --- /dev/null +++ b/files/opencs.cfg @@ -0,0 +1,5 @@ +[Editor] +Record Status Display = Icon and Text +[Window Size] +Width = 640 +Height = 480 diff --git a/files/opencs/added.png b/files/opencs/added.png new file mode 100644 index 000000000..aff7e25d4 Binary files /dev/null and b/files/opencs/added.png differ diff --git a/files/opencs/base.png b/files/opencs/base.png new file mode 100644 index 000000000..4398e2d68 Binary files /dev/null and b/files/opencs/base.png differ diff --git a/files/opencs/modified.png b/files/opencs/modified.png new file mode 100644 index 000000000..d15ad827c Binary files /dev/null and b/files/opencs/modified.png differ diff --git a/files/opencs/raster/activator.png b/files/opencs/raster/activator.png new file mode 100644 index 000000000..0446af22c Binary files /dev/null and b/files/opencs/raster/activator.png differ diff --git a/files/opencs/raster/added.png b/files/opencs/raster/added.png new file mode 100644 index 000000000..ddd9c2108 Binary files /dev/null and b/files/opencs/raster/added.png differ diff --git a/files/opencs/raster/apparatus.png b/files/opencs/raster/apparatus.png new file mode 100644 index 000000000..3cef537e1 Binary files /dev/null and b/files/opencs/raster/apparatus.png differ diff --git a/files/opencs/raster/armor.png b/files/opencs/raster/armor.png new file mode 100644 index 000000000..fc534c7d1 Binary files /dev/null and b/files/opencs/raster/armor.png differ diff --git a/files/opencs/raster/base.png b/files/opencs/raster/base.png new file mode 100644 index 000000000..4398e2d68 Binary files /dev/null and b/files/opencs/raster/base.png differ diff --git a/files/opencs/raster/body-part.png b/files/opencs/raster/body-part.png new file mode 100644 index 000000000..333c5d523 Binary files /dev/null and b/files/opencs/raster/body-part.png differ diff --git a/files/opencs/raster/book.png b/files/opencs/raster/book.png new file mode 100644 index 000000000..3afa9e8aa Binary files /dev/null and b/files/opencs/raster/book.png differ diff --git a/files/opencs/raster/clothing.png b/files/opencs/raster/clothing.png new file mode 100644 index 000000000..88c9b6ab8 Binary files /dev/null and b/files/opencs/raster/clothing.png differ diff --git a/files/opencs/raster/container.png b/files/opencs/raster/container.png new file mode 100644 index 000000000..2a6ed01eb Binary files /dev/null and b/files/opencs/raster/container.png differ diff --git a/files/opencs/raster/creature.png b/files/opencs/raster/creature.png new file mode 100644 index 000000000..99cf9c87c Binary files /dev/null and b/files/opencs/raster/creature.png differ diff --git a/files/opencs/raster/dialogoue-info.png b/files/opencs/raster/dialogoue-info.png new file mode 100644 index 000000000..f6743d43c Binary files /dev/null and b/files/opencs/raster/dialogoue-info.png differ diff --git a/files/opencs/raster/dialogoue-journal.png b/files/opencs/raster/dialogoue-journal.png new file mode 100644 index 000000000..b6a95c538 Binary files /dev/null and b/files/opencs/raster/dialogoue-journal.png differ diff --git a/files/opencs/raster/dialogoue-regular.png b/files/opencs/raster/dialogoue-regular.png new file mode 100644 index 000000000..f9b8d252d Binary files /dev/null and b/files/opencs/raster/dialogoue-regular.png differ diff --git a/files/opencs/raster/dialogue-greeting.png b/files/opencs/raster/dialogue-greeting.png new file mode 100644 index 000000000..a35e1fe6d Binary files /dev/null and b/files/opencs/raster/dialogue-greeting.png differ diff --git a/files/opencs/raster/dialogue-persuasion.png b/files/opencs/raster/dialogue-persuasion.png new file mode 100644 index 000000000..5bc5d6113 Binary files /dev/null and b/files/opencs/raster/dialogue-persuasion.png differ diff --git a/files/opencs/raster/dialogue-speech.png b/files/opencs/raster/dialogue-speech.png new file mode 100644 index 000000000..11eb9f1ca Binary files /dev/null and b/files/opencs/raster/dialogue-speech.png differ diff --git a/files/opencs/raster/door.png b/files/opencs/raster/door.png new file mode 100644 index 000000000..aa48858ef Binary files /dev/null and b/files/opencs/raster/door.png differ diff --git a/files/opencs/raster/ingredient.png b/files/opencs/raster/ingredient.png new file mode 100644 index 000000000..6b36d008d Binary files /dev/null and b/files/opencs/raster/ingredient.png differ diff --git a/files/opencs/raster/leveled-creature.png b/files/opencs/raster/leveled-creature.png new file mode 100644 index 000000000..ad4a7c6f8 Binary files /dev/null and b/files/opencs/raster/leveled-creature.png differ diff --git a/files/opencs/raster/light.png b/files/opencs/raster/light.png new file mode 100644 index 000000000..c606fcd98 Binary files /dev/null and b/files/opencs/raster/light.png differ diff --git a/files/opencs/raster/lockpick.png b/files/opencs/raster/lockpick.png new file mode 100644 index 000000000..d9bd27f5e Binary files /dev/null and b/files/opencs/raster/lockpick.png differ diff --git a/files/opencs/raster/miscellaneous.png b/files/opencs/raster/miscellaneous.png new file mode 100644 index 000000000..744bcd9db Binary files /dev/null and b/files/opencs/raster/miscellaneous.png differ diff --git a/files/opencs/raster/modified.png b/files/opencs/raster/modified.png new file mode 100644 index 000000000..39bd182ac Binary files /dev/null and b/files/opencs/raster/modified.png differ diff --git a/files/opencs/raster/npc.png b/files/opencs/raster/npc.png new file mode 100644 index 000000000..7a07f26df Binary files /dev/null and b/files/opencs/raster/npc.png differ diff --git a/files/opencs/raster/potion.png b/files/opencs/raster/potion.png new file mode 100644 index 000000000..678f61fbf Binary files /dev/null and b/files/opencs/raster/potion.png differ diff --git a/files/opencs/raster/probe.png b/files/opencs/raster/probe.png new file mode 100644 index 000000000..01536186d Binary files /dev/null and b/files/opencs/raster/probe.png differ diff --git a/files/opencs/raster/random-item.png b/files/opencs/raster/random-item.png new file mode 100644 index 000000000..7b8e68e60 Binary files /dev/null and b/files/opencs/raster/random-item.png differ diff --git a/files/opencs/raster/removed.png b/files/opencs/raster/removed.png new file mode 100644 index 000000000..2354bc743 Binary files /dev/null and b/files/opencs/raster/removed.png differ diff --git a/files/opencs/raster/repair.png b/files/opencs/raster/repair.png new file mode 100644 index 000000000..6cf1c0aac Binary files /dev/null and b/files/opencs/raster/repair.png differ diff --git a/files/opencs/raster/sound.png b/files/opencs/raster/sound.png new file mode 100644 index 000000000..b072acf76 Binary files /dev/null and b/files/opencs/raster/sound.png differ diff --git a/files/opencs/raster/soundgen.png b/files/opencs/raster/soundgen.png new file mode 100644 index 000000000..70ae43a1d Binary files /dev/null and b/files/opencs/raster/soundgen.png differ diff --git a/files/opencs/raster/static.png b/files/opencs/raster/static.png new file mode 100644 index 000000000..b53be12d9 Binary files /dev/null and b/files/opencs/raster/static.png differ diff --git a/files/opencs/raster/weapon.png b/files/opencs/raster/weapon.png new file mode 100644 index 000000000..3d4b53466 Binary files /dev/null and b/files/opencs/raster/weapon.png differ diff --git a/files/opencs/removed.png b/files/opencs/removed.png new file mode 100644 index 000000000..2ca9e094b Binary files /dev/null and b/files/opencs/removed.png differ diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index ecfab44a2..926bda064 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -1,5 +1,9 @@ opencs.png + added.png + modified.png + removed.png + base.png 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..56c8e6c6f --- /dev/null +++ b/files/opencs/scalable/referenceable-record/book.svg @@ -0,0 +1,687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..962a14ed1 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/ingredient.svg @@ -0,0 +1,1107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..3bd5307f7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/light.svg @@ -0,0 +1,1508 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..d83649f50 --- /dev/null +++ b/files/opencs/scalable/status/added.svg @@ -0,0 +1,932 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/files/opencs/scalable/status/base.svg b/files/opencs/scalable/status/base.svg new file mode 100644 index 000000000..90c9bc319 --- /dev/null +++ b/files/opencs/scalable/status/base.svg @@ -0,0 +1,942 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..8d2ec4710 --- /dev/null +++ b/files/opencs/scalable/status/modified.svg @@ -0,0 +1,1155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..c879af91f --- /dev/null +++ b/files/opencs/scalable/status/removed.svg @@ -0,0 +1,935 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + 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 + + + + + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 69aa20883..613f12432 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -6,6 +6,7 @@ resolution x = 800 resolution y = 600 fullscreen = false +screen = 0 # Render system # blank means default diff --git a/files/ui/graphicspage.ui b/files/ui/graphicspage.ui index 5c330cebd..7e9fe00d9 100644 --- a/files/ui/graphicspage.ui +++ b/files/ui/graphicspage.ui @@ -58,6 +58,13 @@ + + + Screen: + + + + Resolution: @@ -71,6 +78,9 @@ + + + diff --git a/files/ui/playpage.ui b/files/ui/playpage.ui index c0320de1e..bf883b96e 100644 --- a/files/ui/playpage.ui +++ b/files/ui/playpage.ui @@ -2,9 +2,17 @@ PlayPage + + + 0 + 0 + 274 + 317 + + - + #Scroll { background-image: url(":/images/playpage-background.png"); @@ -13,15 +21,6 @@ } - - QFrame::StyledPanel - - - QFrame::Plain - - - 0 - 30 diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index bbe633847..550e71b3c 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -146,6 +146,16 @@ namespace Physic return collisionMode && onGround; } + void PhysicActor::disableCollisionBody() + { + mEngine->dynamicsWorld->removeRigidBody(mBody); + } + + void PhysicActor::enableCollisionBody() + { + mEngine->dynamicsWorld->addRigidBody(mBody); + } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 80c681fe5..baeb31678 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -129,6 +129,9 @@ namespace Physic bool getOnGround() const; + void disableCollisionBody(); + void enableCollisionBody(); + //HACK: in Visual Studio 2010 and presumably above, this structures alignment // must be 16, but the built in operator new & delete don't properly // perform this alignment. diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp new file mode 100644 index 000000000..3dd584078 --- /dev/null +++ b/libs/openengine/ogre/imagerotate.cpp @@ -0,0 +1,88 @@ +#include "imagerotate.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Ogre; +using namespace OEngine::Render; + +void ImageRotate::rotate(const std::string& sourceImage, const std::string& destImage, const float angle) +{ + Root* root = Ogre::Root::getSingletonPtr(); + + std::string destImageRot = std::string(destImage) + std::string("_rot"); + + SceneManager* sceneMgr = root->createSceneManager(ST_GENERIC); + Camera* camera = sceneMgr->createCamera("ImageRotateCamera"); + + MaterialPtr material = MaterialManager::getSingleton().create("ImageRotateMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + material->getTechnique(0)->getPass(0)->setLightingEnabled(false); + material->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); + TextureUnitState* tus = material->getTechnique(0)->getPass(0)->createTextureUnitState(sourceImage); + Degree deg(angle); + tus->setTextureRotate(Radian(deg.valueRadians())); + tus->setTextureAddressingMode(TextureUnitState::TAM_BORDER); + tus->setTextureBorderColour(ColourValue(0, 0, 0, 0)); + + Rectangle2D* rect = new Rectangle2D(true); + rect->setCorners(-1.0, 1.0, 1.0, -1.0); + rect->setMaterial("ImageRotateMaterial"); + // Render the background before everything else + rect->setRenderQueueGroup(RENDER_QUEUE_BACKGROUND); + + // Use infinite AAB to always stay visible + AxisAlignedBox aabInf; + aabInf.setInfinite(); + rect->setBoundingBox(aabInf); + + // Attach background to the scene + SceneNode* node = sceneMgr->getRootSceneNode()->createChildSceneNode(); + node->attachObject(rect); + + // retrieve image width and height + TexturePtr sourceTexture = TextureManager::getSingleton().getByName(sourceImage); + unsigned int width = sourceTexture->getWidth(); + unsigned int height = sourceTexture->getHeight(); + + TexturePtr destTextureRot = TextureManager::getSingleton().createManual( + destImageRot, + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + width, height, + 0, + PF_FLOAT16_RGBA, + TU_RENDERTARGET); + + RenderTarget* rtt = destTextureRot->getBuffer()->getRenderTarget(); + rtt->setAutoUpdated(false); + Viewport* vp = rtt->addViewport(camera); + vp->setOverlaysEnabled(false); + vp->setShadowsEnabled(false); + vp->setBackgroundColour(ColourValue(0,0,0,0)); + + rtt->update(); + + //copy the rotated image to a static texture + TexturePtr destTexture = TextureManager::getSingleton().createManual( + destImage, + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + TEX_TYPE_2D, + width, height, + 0, + PF_FLOAT16_RGBA, + Ogre::TU_STATIC); + + destTexture->getBuffer()->blit(destTextureRot->getBuffer()); + + // remove all the junk we've created + TextureManager::getSingleton().remove(destImageRot); + MaterialManager::getSingleton().remove("ImageRotateMaterial"); + root->destroySceneManager(sceneMgr); + delete rect; +} diff --git a/libs/openengine/ogre/imagerotate.hpp b/libs/openengine/ogre/imagerotate.hpp new file mode 100644 index 000000000..a3f6d662f --- /dev/null +++ b/libs/openengine/ogre/imagerotate.hpp @@ -0,0 +1,27 @@ +#ifndef OENGINE_OGRE_IMAGEROTATE_HPP +#define OENGINE_OGRE_IMAGEROTATE_HPP + +#include + +namespace OEngine +{ +namespace Render +{ + + /// Rotate an image by certain degrees and save as file, uses the GPU + /// Make sure Ogre Root is initialised before calling + class ImageRotate + { + public: + /** + * @param source image (file name - has to exist in an resource group) + * @param name of the destination texture to save to (in memory) + * @param angle in degrees to turn + */ + static void rotate(const std::string& sourceImage, const std::string& destImage, const float angle); + }; + +} +} + +#endif diff --git a/libs/openengine/ogre/osx_utils.h b/libs/openengine/ogre/osx_utils.h new file mode 100644 index 000000000..f651db604 --- /dev/null +++ b/libs/openengine/ogre/osx_utils.h @@ -0,0 +1,14 @@ +#ifndef OENGINE_OGRE_OSX_UTILS_H +#define OENGINE_OGRE_OSX_UTILS_H + +#include + +namespace OEngine { +namespace Render { + +extern unsigned long WindowContentViewHandle(SDL_SysWMinfo &info); + +} +} + +#endif diff --git a/libs/openengine/ogre/osx_utils.mm b/libs/openengine/ogre/osx_utils.mm new file mode 100644 index 000000000..7e5660146 --- /dev/null +++ b/libs/openengine/ogre/osx_utils.mm @@ -0,0 +1,16 @@ +#include "osx_utils.h" + +#import + +namespace OEngine { +namespace Render { + +unsigned long WindowContentViewHandle(SDL_SysWMinfo &info) +{ + NSWindow *window = info.info.cocoa.window; + NSView *view = [window contentView]; + return (unsigned long)view; +} + +} +} diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 7be713796..00d94a004 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -2,6 +2,9 @@ #include "fader.hpp" #include "particles.hpp" +#include +#include + #include "OgreRoot.h" #include "OgreRenderWindow.h" #include "OgreLogManager.h" @@ -20,15 +23,15 @@ #include #include -#if defined(__APPLE__) && !defined(__LP64__) -#include +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE +#include "osx_utils.h" #endif using namespace Ogre; using namespace OEngine::Render; -#if defined(__APPLE__) && !defined(__LP64__) +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE CustomRoot::CustomRoot(const Ogre::String& pluginFileName, const Ogre::String& configFileName, @@ -51,29 +54,25 @@ void OgreRenderer::cleanup() delete mRoot; mRoot = NULL; + if (mWindowIconSurface) + SDL_FreeSurface(mWindowIconSurface); + + // If we don't do this, the desktop resolution is not restored on exit + SDL_SetWindowFullscreen(mSDLWindow, 0); + + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + unloadPlugins(); } void OgreRenderer::start() { -#if defined(__APPLE__) && !defined(__LP64__) - // OSX Carbon Message Pump +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + // we need this custom main loop because otherwise Ogre's Carbon message pump will + // steal input events even from our Cocoa window + // There's no way to disable Ogre's message pump other that comment pump code in Ogre's source do { - EventRef event = NULL; - EventTargetRef targetWindow; - targetWindow = GetEventDispatcherTarget(); - - // If we are unable to get the target then we no longer care about events. - if (!targetWindow) return; - - // Grab the next event while possible - while (ReceiveNextEvent(0, NULL, kEventDurationNoWait, true, &event) == noErr) - { - // Dispatch the event - SendEventToEventTarget(event, targetWindow); - ReleaseEvent(event); - } - if (!mRoot->renderOneFrame()) { break; } @@ -174,7 +173,7 @@ void OgreRenderer::configure(const std::string &logPath, // Disable logging log->setDebugOutputEnabled(false); -#if defined(__APPLE__) && !defined(__LP64__) +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE mRoot = new CustomRoot("", "", ""); #else mRoot = new Root("", "", ""); @@ -206,6 +205,7 @@ void OgreRenderer::configure(const std::string &logPath, pluginDir = absPluginPath.string(); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot); + Files::loadOgrePlugin(pluginDir, "RenderSystem_GLES2", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); @@ -266,9 +266,76 @@ 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")); + int pos_x = SDL_WINDOWPOS_UNDEFINED, + pos_y = SDL_WINDOWPOS_UNDEFINED; + + if(settings.fullscreen) + { + SDL_Rect display_bounds; + if(SDL_GetDisplayBounds(settings.screen, &display_bounds) != 0) + throw std::runtime_error("Couldn't get display bounds!"); + pos_x = display_bounds.x; + pos_y = display_bounds.y; + } + + // Create an application window with the following settings: + mSDLWindow = SDL_CreateWindow( + "OpenMW", // window title + pos_x, // initial x position + pos_y, // initial y position + settings.window_x, // width, in pixels + settings.window_y, // height, in pixels + SDL_WINDOW_SHOWN + | (settings.fullscreen ? SDL_WINDOW_FULLSCREEN : 0) + ); + + //get the native whnd + struct SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version); + + if(-1 == SDL_GetWindowWMInfo(mSDLWindow, &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 __MACOSX__ + 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(WindowContentViewHandle(wmInfo)); + 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); + // Set the window icon + if (settings.icon != "") + { + mWindowIconSurface = ogreTextureToSDLSurface(settings.icon); + SDL_SetWindowIcon(mSDLWindow, mWindowIconSurface); + } + // create the semi-transparent black background texture used by the GUI. // has to be created in code with TU_DYNAMIC_WRITE_ONLY param // so that it can be modified at runtime. @@ -306,7 +373,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) @@ -323,3 +394,59 @@ void OgreRenderer::setFov(float fov) { mCamera->setFOVy(Degree(fov)); } + +SDL_Surface* OgreRenderer::ogreTextureToSDLSurface(const std::string& name) +{ + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().load(name, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); + if (texture.isNull()) + { + std::stringstream error; + error << "Window icon not found: " << name; + throw std::runtime_error(error.str()); + } + Ogre::Image image; + texture->convertToImage(image); + + SDL_Surface* surface = SDL_CreateRGBSurface(0,texture->getWidth(),texture->getHeight(),32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); + + //copy the Ogre texture to an SDL surface + for(size_t x = 0; x < texture->getWidth(); ++x) + { + for(size_t y = 0; y < texture->getHeight(); ++y) + { + Ogre::ColourValue clr = image.getColourAt(x, y, 0); + + //set the pixel on the SDL surface to the same value as the Ogre texture's + 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; + Uint32 pixel = SDL_MapRGBA(surface->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255); + 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; + } + } + } + return surface; +} diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 962ae4f2e..f4b38c52d 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -27,13 +27,16 @@ #include "OgreTexture.h" #include -#if defined(__APPLE__) && !defined(__LP64__) +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE #include #endif +struct SDL_Window; +struct SDL_Surface; + namespace Ogre { -#if !defined(__APPLE__) || defined(__LP64__) +#if OGRE_PLATFORM != OGRE_PLATFORM_APPLE class Root; #endif class RenderWindow; @@ -53,10 +56,12 @@ namespace OEngine bool vsync; bool fullscreen; int window_x, window_y; + int screen; std::string fsaa; + std::string icon; }; -#if defined(__APPLE__) && !defined(__LP64__) +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE class CustomRoot : public Ogre::Root { public: bool isQueuedEnd() const; @@ -71,12 +76,14 @@ namespace OEngine class OgreRenderer { -#if defined(__APPLE__) && !defined(__LP64__) +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE CustomRoot *mRoot; #else Ogre::Root *mRoot; #endif Ogre::RenderWindow *mWindow; + SDL_Window *mSDLWindow; + SDL_Surface *mWindowIconSurface; Ogre::SceneManager *mScene; Ogre::Camera *mCamera; Ogre::Viewport *mView; @@ -100,13 +107,17 @@ namespace OEngine std::vector mAffectorFactories; bool logging; + SDL_Surface* ogreTextureToSDLSurface(const std::string& name); + public: OgreRenderer() : mRoot(NULL) , mWindow(NULL) + , mSDLWindow(NULL) , mScene(NULL) , mCamera(NULL) , mView(NULL) + , mWindowIconSurface(NULL) #ifdef ENABLE_PLUGIN_CgProgramManager , mCgPlugin(NULL) #endif @@ -176,6 +187,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; } diff --git a/readme.txt b/readme.txt index f8361780c..67c02cc61 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.23.0 +Version: 0.24.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -94,6 +94,54 @@ Allowed options: CHANGELOG +0.24.0 + +Bug #284: Book's text misalignment +Bug #445: Camera able to get slightly below floor / terrain +Bug #582: Seam issue in Red Mountain +Bug #632: Journal Next Button shows white square +Bug #653: IndexedStore ignores index +Bug #694: Parser does not recognize float values starting with . +Bug #699: Resource handling broken with Ogre 1.9 trunk +Bug #718: components/esm/loadcell is using the mwworld subsystem +Bug #729: Levelled item list tries to add nonexistent item +Bug #730: Arrow buttons in the settings menu do not work. +Bug #732: Erroneous behavior when binding keys +Bug #733: Unclickable dialogue topic +Bug #734: Book empty line problem +Bug #738: OnDeath only works with implicit references +Bug #740: Script compiler fails on scripts with special names +Bug #742: Wait while no clipping +Bug #743: Problem with changeweather console command +Bug #744: No wait dialogue after starting a new game +Bug #748: Player is not able to unselect objects with the console +Bug #751: AddItem should only spawn a message box when called from dialogue +Bug #752: The enter button has several functions in trade and looting that is not impelemted. +Bug #753: Fargoth's Ring Quest Strange Behavior +Bug #755: Launcher writes duplicate lines into settings.cfg +Bug #759: Second quest in mages guild does not work +Bug #763: Enchantment cast cost is wrong +Bug #770: The "Take" and "Close" buttons in the scroll GUI are stretched incorrectly +Bug #773: AIWander Isn't Being Passed The Correct idle Values +Bug #778: The journal can be opened at the start of a new game +Bug #779: Divayth Fyr starts as dead +Bug #787: "Batch count" on detailed FPS counter gets cut-off +Bug #788: chargen scroll layout does not match vanilla +Feature #60: Atlethics Skill +Feature #65: Security Skill +Feature #74: Interaction with non-load-doors +Feature #98: Render Weapon and Shield +Feature #102: AI Package: Escort, EscortCell +Feature #182: Advanced Journal GUI +Feature #288: Trading enhancements +Feature #405: Integrate "new game" into the menu +Feature #537: Highlight dialogue topic links +Feature #658: Rotate, RotateWorld script instructions and local rotations +Feature #690: Animation Layering +Feature #722: Night Eye/Blind magic effects +Feature #735: Move, MoveWorld script instructions. +Feature #760: Non-removable corpses + 0.23.0 Bug #522: Player collides with placeable items