diff --git a/.gitignore b/.gitignore index b3bb8d82d..26ba80e1a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ cmake_install.cmake Makefile makefile data +*.kdev4 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d2a4cf0d3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "extern/shiny"] + path = extern/shiny + url = git://github.com/scrawl/shiny.git diff --git a/CMakeLists.txt b/CMakeLists.txt index b83935bdc..e3cc8df3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 15) +set (OPENMW_VERSION_MINOR 16) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -37,6 +37,9 @@ option(USE_FFMPEG "use ffmpeg for sound" OFF) option(USE_AUDIERE "use audiere for sound" OFF) option(USE_MPG123 "use mpg123 + libsndfile for sound" ON) +# OS X deployment +option(OPENMW_OSX_DEPLOYMENT OFF) + find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems") # Location of morrowind data files @@ -93,9 +96,8 @@ ENDIF() set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) -set(MANGLE_VFS ${LIBDIR}/mangle/vfs/servers/ogre_vfs.cpp) set(MANGLE_INPUT ${LIBDIR}/mangle/input/servers/ois_driver.cpp) -set(MANGLE_ALL ${MANGLE_VFS} ${MANGLE_INPUT}) +set(MANGLE_ALL ${MANGLE_INPUT}) source_group(libs\\mangle FILES ${MANGLE_ALL}) set(OENGINE_OGRE @@ -187,14 +189,24 @@ if (UNIX AND NOT APPLE) find_package (Threads) endif() +# find boost without components so we can use Boost_VERSION +find_package(Boost REQUIRED) + +set(BOOST_COMPONENTS system filesystem program_options thread) + +if (Boost_VERSION LESS 104900) + set(SHINY_USE_WAVE_SYSTEM_INSTALL "TRUE") + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} wave) +endif() + find_package(OGRE REQUIRED) find_package(MyGUI REQUIRED) -find_package(Boost REQUIRED COMPONENTS system filesystem program_options thread) +find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(OIS REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) IF(OGRE_STATIC) -find_package(Cg REQUIRED) +find_package(Cg) IF(WIN32) set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_Direct3D9_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS}) ELSE(WIN32) @@ -221,8 +233,48 @@ if (APPLE) ${OGRE_Plugin_OctreeSceneManager_LIBRARY_REL} ${OGRE_Plugin_CgProgramManager_LIBRARY_REL} ${OGRE_Plugin_ParticleFX_LIBRARY_REL}) + + if (${OGRE_PLUGIN_DIR_REL}}) + set(OGRE_PLUGINS_REL_FOUND TRUE) + endif () + + if (${OGRE_PLUGIN_DIR_DBG}) + set(OGRE_PLUGINS_DBG_FOUND TRUE) + endif () + + if (${OGRE_PLUGINS_REL_FOUND}) + set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) + else () + set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) + endif () + + #set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/") + + configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist + "${APP_BUNDLE_DIR}/Contents/Info.plist") + + configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns + "${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY) endif (APPLE) + +# Set up Ogre plugin folder & debug suffix +if (APPLE) + # Ogre on OS X doesn't use "_d" suffix (see Ogre's CMakeLists.txt) + add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="") +else () + add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d") +endif() + +add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}") +add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}") +if (APPLE AND OPENMW_OSX_DEPLOYMENT) + add_definitions(-DOGRE_PLUGIN_DIR="${APP_BUNDLE_NAME}/Contents/Plugins") +else() + add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") +endif() + + add_subdirectory(files/) add_subdirectory(files/mygui) @@ -247,53 +299,12 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg "${OpenMW_BINARY_DIR}/openmw.cfg.install") -if (WIN32) - configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.win32 - "${OpenMW_BINARY_DIR}/plugins.cfg" COPYONLY) -endif (WIN32) if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux - "${OpenMW_BINARY_DIR}/plugins.cfg") - configure_file(${OpenMW_SOURCE_DIR}/files/openmw.desktop "${OpenMW_BINARY_DIR}/openmw.desktop") endif() -if (APPLE) - if (${OGRE_PLUGIN_DIR_REL}}) - set(OGRE_PLUGINS_REL_FOUND TRUE) - endif () - - if (${OGRE_PLUGIN_DIR_DBG}) - set(OGRE_PLUGINS_DBG_FOUND TRUE) - endif () - - if (${OGRE_PLUGINS_REL_FOUND}) - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL}) - else () - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) - endif () - - set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/") - - configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac - "${OpenMW_BINARY_DIR}/plugins.cfg") - - set(OGRE_PLUGIN_DIR_2 ${OGRE_PLUGIN_DIR}) - set(OGRE_PLUGIN_DIR "") - configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.mac - "${OpenMW_BINARY_DIR}/plugins.cfg.install") - set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_2}) - - configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist - "${APP_BUNDLE_DIR}/Contents/Info.plist") - - configure_file(${OpenMW_SOURCE_DIR}/files/mac/openmw.icns - "${APP_BUNDLE_DIR}/Contents/Resources/OpenMW.icns" COPYONLY) -endif (APPLE) - - # Compiler settings if (CMAKE_COMPILER_IS_GNUCC) add_definitions (-Wall -Wextra -Wno-unused-parameter -Wno-reorder) @@ -330,7 +341,6 @@ 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}/plugins.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") @@ -347,7 +357,7 @@ if(DPKG_PROGRAM) SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "nvidia-cg-toolkit (>= 2.1), libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-filesystem1.46.1 (>= 1.46.1), libboost-program-options1.46.1 (>= 1.46.1), libboost-system1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") @@ -368,7 +378,6 @@ if(WIN32) INSTALL(FILES ${dll_files} DESTINATION ".") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES - "${OpenMW_BINARY_DIR}/plugins.cfg" "${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_SOURCE_DIR}/GPL3.txt" "${OpenMW_SOURCE_DIR}/OFL.txt" @@ -432,6 +441,9 @@ if(WIN32) include(CPack) endif(WIN32) +# Extern +add_subdirectory (extern/shiny) + # Components add_subdirectory (components) @@ -537,7 +549,6 @@ if (APPLE) install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) - install(FILES "${OpenMW_BINARY_DIR}/plugins.cfg.install" RENAME "plugins.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index f417d5c60..4888d3ceb 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -187,7 +187,7 @@ int main(int argc, char**argv) case REC_ALCH: { Potion p; - p.load(esm); + p.load(esm, id); if(quiet) break; cout << " Name: " << p.name << endl; break; diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index f3c5962ca..8545be835 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -140,7 +140,7 @@ DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent) createActions(); setupConfig(); - setupDataFiles(); + //setupDataFiles(); } @@ -189,7 +189,7 @@ void DataFilesPage::setupConfig() } -void DataFilesPage::setupDataFiles() +bool DataFilesPage::setupDataFiles() { // We use the Configuration Manager to retrieve the configuration values boost::program_options::variables_map variables; @@ -245,21 +245,15 @@ void DataFilesPage::setupDataFiles() mCfgMgr.processPaths(mDataDirs); } else { // Cancel from within the dir selection dialog - break; + return false; } } else { // Cancel - break; + return false; } } - // Check if cancel was clicked because we can't exit from while loop - if (mDataDirs.empty()) { - QApplication::exit(1); - return; - } - // Create a file collection for the data dirs Files::Collections fileCollections(mDataDirs, !variables["fs-strict"].as()); @@ -362,6 +356,7 @@ void DataFilesPage::setupDataFiles() } readConfig(); + return true; } void DataFilesPage::createActions() @@ -1076,7 +1071,7 @@ void DataFilesPage::writeConfig(QString profile) Please make sure you have the right permissions and try again.
").arg(pathStr)); msgBox.exec(); - qApp->exit(1); + qApp->quit(); return; } } @@ -1093,7 +1088,7 @@ void DataFilesPage::writeConfig(QString profile) Please make sure you have the right permissions and try again.
").arg(file.fileName())); msgBox.exec(); - qApp->exit(1); + qApp->quit(); return; } @@ -1124,7 +1119,7 @@ void DataFilesPage::writeConfig(QString profile) Please make sure you have the right permissions and try again.
").arg(file.fileName())); msgBox.exec(); - qApp->exit(1); + qApp->quit(); return; } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index ad5e90511..5078f6428 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -34,6 +34,7 @@ public: ComboBox *mProfilesComboBox; void writeConfig(QString profile = QString()); + bool setupDataFiles(); public slots: void masterSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); @@ -92,7 +93,6 @@ private: void removePlugins(const QModelIndex &index); void uncheckPlugins(); void createActions(); - void setupDataFiles(); void setupConfig(); void readConfig(); void scrollToSelection(); diff --git a/apps/launcher/filedialog.cpp b/apps/launcher/filedialog.cpp index 595501b91..16d677533 100644 --- a/apps/launcher/filedialog.cpp +++ b/apps/launcher/filedialog.cpp @@ -28,13 +28,13 @@ QString FileDialog::getExistingDirectory(QWidget *parent, // create a non-native file dialog FileDialog dialog; dialog.setFileMode(DirectoryOnly); - dialog.setOptions(options & (DontUseNativeDialog | ShowDirsOnly)); + dialog.setOptions(options |= QFileDialog::DontUseNativeDialog | QFileDialog::ShowDirsOnly | QFileDialog::ReadOnly); if (!caption.isEmpty()) dialog.setWindowTitle(caption); if (!dir.isEmpty()) - dialog.setDirectory(dir); + dialog.setDirectory(dir); if (dialog.exec() == QDialog::Accepted) { return dialog.selectedFiles().value(0); diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 22a9ca5be..c3c39cffc 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -1,12 +1,29 @@ -#include "graphicspage.hpp" - #include -#include +#include + +#include +#include #include +#include #include +#include "graphicspage.hpp" +#include "naturalsort.hpp" + +QString getAspect(int x, int y) +{ + int gcd = boost::math::gcd (x, y); + int xaspect = x / gcd; + int yaspect = y / gcd; + // special case: 8 : 5 is usually referred to as 16:10 + if (xaspect == 8 && yaspect == 5) + return QString("16:10"); + + return QString(QString::number(xaspect) + ":" + QString::number(yaspect)); +} + GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent) : QWidget(parent) , mCfgMgr(cfg) @@ -21,83 +38,49 @@ GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent) renderSystemLayout->addWidget(rendererLabel, 0, 0, 1, 1); renderSystemLayout->addWidget(mRendererComboBox, 0, 1, 1, 1); - QVBoxLayout *rendererGroupLayout = new QVBoxLayout(rendererGroup); - - rendererGroupLayout->addLayout(renderSystemLayout); - // Display QGroupBox *displayGroup = new QGroupBox(tr("Display"), this); - mDisplayStackedWidget = new QStackedWidget(displayGroup); + mVSyncCheckBox = new QCheckBox(tr("Vertical Sync"), displayGroup); + mFullScreenCheckBox = new QCheckBox(tr("Full Screen"), displayGroup); - QVBoxLayout *displayGroupLayout = new QVBoxLayout(displayGroup); - QSpacerItem *vSpacer3 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding); + QLabel *antiAliasingLabel = new QLabel(tr("Antialiasing:"), displayGroup); + QLabel *resolutionLabel = new QLabel(tr("Resolution:"), displayGroup); - displayGroupLayout->addWidget(mDisplayStackedWidget); - displayGroupLayout->addItem(vSpacer3); + mResolutionComboBox = new QComboBox(displayGroup); + mAntiAliasingComboBox = new QComboBox(displayGroup); + + QVBoxLayout *rendererGroupLayout = new QVBoxLayout(rendererGroup); + rendererGroupLayout->addLayout(renderSystemLayout); + + QGridLayout *displayGroupLayout = new QGridLayout(displayGroup); + displayGroupLayout->addWidget(mVSyncCheckBox, 0, 0, 1, 1); + displayGroupLayout->addWidget(mFullScreenCheckBox, 1, 0, 1, 1); + displayGroupLayout->addWidget(antiAliasingLabel, 2, 0, 1, 1); + displayGroupLayout->addWidget(mAntiAliasingComboBox, 2, 1, 1, 1); + displayGroupLayout->addWidget(resolutionLabel, 3, 0, 1, 1); + displayGroupLayout->addWidget(mResolutionComboBox, 3, 1, 1, 1); // Layout for the whole page QVBoxLayout *pageLayout = new QVBoxLayout(this); + QSpacerItem *vSpacer1 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding); pageLayout->addWidget(rendererGroup); pageLayout->addWidget(displayGroup); + pageLayout->addItem(vSpacer1); connect(mRendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&))); - - createPages(); - setupConfig(); - setupOgre(); - - readConfig(); } -void GraphicsPage::createPages() +bool GraphicsPage::setupOgre() { - QWidget *main = new QWidget(); - QGridLayout *grid = new QGridLayout(main); - - mVSyncCheckBox = new QCheckBox(tr("Vertical Sync"), main); - grid->addWidget(mVSyncCheckBox, 0, 0, 1, 1); - - mFullScreenCheckBox = new QCheckBox(tr("Full Screen"), main); - grid->addWidget(mFullScreenCheckBox, 1, 0, 1, 1); - - QLabel *antiAliasingLabel = new QLabel(tr("Antialiasing:"), main); - mAntiAliasingComboBox = new QComboBox(main); - grid->addWidget(antiAliasingLabel, 2, 0, 1, 1); - grid->addWidget(mAntiAliasingComboBox, 2, 1, 1, 1); - - QLabel *resolutionLabel = new QLabel(tr("Resolution:"), main); - mResolutionComboBox = new QComboBox(main); - grid->addWidget(resolutionLabel, 3, 0, 1, 1); - grid->addWidget(mResolutionComboBox, 3, 1, 1, 1); - - QSpacerItem *vSpacer1 = new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding); - grid->addItem(vSpacer1, 4, 0, 1, 1); - - mDisplayStackedWidget->addWidget(main); -} - -void GraphicsPage::setupConfig() -{ -} - -void GraphicsPage::setupOgre() -{ - QString pluginCfg = mCfgMgr.getPluginsConfigPath().string().c_str(); - QFile file(pluginCfg); - // Create a log manager so we can surpress debug text to stdout/stderr Ogre::LogManager* logMgr = OGRE_NEW Ogre::LogManager; logMgr->createLog((mCfgMgr.getLogPath().string() + "/launcherOgre.log"), true, false, false); try { - #if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9) mOgre = new Ogre::Root("", "", "./launcherOgre.log"); - #else - mOgre = new Ogre::Root(pluginCfg.toStdString(), "", "./launcherOgre.log"); - #endif } catch(Ogre::Exception &ex) { @@ -107,25 +90,47 @@ void GraphicsPage::setupOgre() msgBox.setIcon(QMessageBox::Critical); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Failed to create the Ogre::Root object

\ - Make sure the plugins.cfg is present and valid.

\ Press \"Show Details...\" for more information.
")); msgBox.setDetailedText(ogreError); msgBox.exec(); qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError)); - - qApp->exit(1); - return; + return false; } - #ifdef ENABLE_PLUGIN_GL - mGLPlugin = new Ogre::GLPlugin(); - mOgre->installPlugin(mGLPlugin); - #endif - #ifdef ENABLE_PLUGIN_Direct3D9 - mD3D9Plugin = new Ogre::D3D9Plugin(); - mOgre->installPlugin(mD3D9Plugin); - #endif + + std::string pluginDir; + const char* pluginEnv = getenv("OPENMW_OGRE_PLUGIN_DIR"); + if (pluginEnv) + pluginDir = pluginEnv; + else + { +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + pluginDir = ".\\"; +#endif +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + pluginDir = OGRE_PLUGIN_DIR; +#endif +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX + pluginDir = OGRE_PLUGIN_DIR_REL; +#endif + } + + boost::filesystem::path absPluginPath = boost::filesystem::absolute(boost::filesystem::path(pluginDir)); + + pluginDir = absPluginPath.string(); + + Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mOgre); + Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mOgre); + +#ifdef ENABLE_PLUGIN_GL + mGLPlugin = new Ogre::GLPlugin(); + mOgre->installPlugin(mGLPlugin); +#endif +#ifdef ENABLE_PLUGIN_Direct3D9 + mD3D9Plugin = new Ogre::D3D9Plugin(); + mOgre->installPlugin(mD3D9Plugin); +#endif // Get the available renderers and put them in the combobox const Ogre::RenderSystemList &renderers = mOgre->getAvailableRenderers(); @@ -135,6 +140,26 @@ void GraphicsPage::setupOgre() mRendererComboBox->addItem((*r)->getName().c_str()); } + QString openGLName = QString("OpenGL Rendering Subsystem"); + QString direct3DName = QString("Direct3D9 Rendering Subsystem"); + + // Create separate rendersystems + mOpenGLRenderSystem = mOgre->getRenderSystemByName(openGLName.toStdString()); + mDirect3DRenderSystem = mOgre->getRenderSystemByName(direct3DName.toStdString()); + + if (!mOpenGLRenderSystem && !mDirect3DRenderSystem) { + QMessageBox msgBox; + msgBox.setWindowTitle(tr("Error creating renderer")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not select a valid render system

\ + Please make sure the plugins.cfg file exists and contains a valid rendering plugin.
")); + msgBox.exec(); + + return false; + } + + // Now fill the GUI elements int index = mRendererComboBox->findText(QString::fromStdString(Settings::Manager::getString("render system", "Video"))); if ( index != -1) { @@ -143,37 +168,19 @@ void GraphicsPage::setupOgre() else { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 - mRendererComboBox->setCurrentIndex(mRendererComboBox->findText("Direct3D9 Rendering Subsystem")); + mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(direct3DName)); #else - mRendererComboBox->setCurrentIndex(mRendererComboBox->findText("OpenGL Rendering Subsystem")); + mRendererComboBox->setCurrentIndex(mRendererComboBox->findText(openGLName)); #endif } - // Create separate rendersystems - QString openGLName = mRendererComboBox->itemText(mRendererComboBox->findText(QString("OpenGL"), Qt::MatchStartsWith)); - QString direct3DName = mRendererComboBox->itemText(mRendererComboBox->findText(QString("Direct3D"), Qt::MatchStartsWith)); - - mOpenGLRenderSystem = mOgre->getRenderSystemByName(openGLName.toStdString()); - mDirect3DRenderSystem = mOgre->getRenderSystemByName(direct3DName.toStdString()); - - if (!mOpenGLRenderSystem && !mDirect3DRenderSystem) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error creating renderer"); - msgBox.setIcon(QMessageBox::Critical); - msgBox.setStandardButtons(QMessageBox::Ok); - msgBox.setText(tr("
Could not select a valid render system

\ - Please make sure the plugins.cfg file exists and contains a valid rendering plugin.
")); - msgBox.exec(); - - qApp->exit(1); - return; - } - - // Now fill the GUI elements mAntiAliasingComboBox->clear(); mResolutionComboBox->clear(); mAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem)); - mResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mSelectedRenderSystem)); + mResolutionComboBox->addItems(getAvailableResolutions(mSelectedRenderSystem)); + + readConfig(); + return true; } void GraphicsPage::readConfig() @@ -188,9 +195,10 @@ void GraphicsPage::readConfig() if (aaIndex != -1) mAntiAliasingComboBox->setCurrentIndex(aaIndex); - std::string resolution = boost::lexical_cast(Settings::Manager::getInt("resolution x", "Video")) - + " x " + boost::lexical_cast(Settings::Manager::getInt("resolution y", "Video")); - int resIndex = mResolutionComboBox->findText(QString::fromStdString(resolution)); + QString resolution = QString::number(Settings::Manager::getInt("resolution x", "Video")); + resolution.append(" x " + QString::number(Settings::Manager::getInt("resolution y", "Video"))); + + int resIndex = mResolutionComboBox->findText(resolution, Qt::MatchStartsWith); if (resIndex != -1) mResolutionComboBox->setCurrentIndex(resIndex); } @@ -202,11 +210,12 @@ void GraphicsPage::writeConfig() Settings::Manager::setString("antialiasing", "Video", mAntiAliasingComboBox->currentText().toStdString()); Settings::Manager::setString("render system", "Video", mRendererComboBox->currentText().toStdString()); - // parse resolution x and y from a string like "800 x 600" - QString resolution = mResolutionComboBox->currentText(); + // Get the current resolution, but with the tabs replaced with a single space + QString resolution = mResolutionComboBox->currentText().simplified(); QStringList tokens = resolution.split(" ", QString::SkipEmptyParts); - int resX = boost::lexical_cast(tokens.at(0).toStdString()); - int resY = boost::lexical_cast(tokens.at(2).toStdString()); + + int resX = tokens.at(0).toInt(); + int resY = tokens.at(2).toInt(); Settings::Manager::setInt("resolution x", "Video", resX); Settings::Manager::setInt("resolution y", "Video", resY); } @@ -228,15 +237,21 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { - if (key == "FSAA" && *opt_it == "0") - result << QString("none"); - else - result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); + result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); } } } + // Sort ascending + qSort(result.begin(), result.end(), naturalSortLessThanCI); + + // Replace the zero option with Off + int index = result.indexOf("MSAA 0"); + + if (index != -1) + result.replace(index, tr("Off")); + return result; } @@ -255,24 +270,36 @@ QStringList GraphicsPage::getAvailableResolutions(Ogre::RenderSystem *renderer) Ogre::StringVector::iterator opt_it; uint idx = 0; + for (opt_it = i->second.possibleValues.begin (); - opt_it != i->second.possibleValues.end (); opt_it++, idx++) + opt_it != i->second.possibleValues.end (); opt_it++, idx++) { QString qval = QString::fromStdString(*opt_it).simplified(); // remove extra tokens after the resolution (for example bpp, can be there or not depending on rendersystem) QStringList tokens = qval.split(" ", QString::SkipEmptyParts); assert (tokens.size() >= 3); QString resolutionStr = tokens.at(0) + QString(" x ") + tokens.at(2); - { - // do not add duplicate resolutions - if (!result.contains(resolutionStr)) - result << resolutionStr; + // do not add duplicate resolutions + if (!result.contains(resolutionStr)) { + + QString aspect = getAspect(tokens.at(0).toInt(),tokens.at(2).toInt()); + + if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10")) { + resolutionStr.append(tr("\t(Widescreen ") + aspect + ")"); + + } else if (aspect == QLatin1String("4:3")) { + resolutionStr.append(tr("\t(Standard 4:3)")); + } + + result << resolutionStr; } } - } + // Sort the resolutions in descending order + qSort(result.begin(), result.end(), naturalSortGreaterThanCI); + return result; } diff --git a/apps/launcher/graphicspage.hpp b/apps/launcher/graphicspage.hpp index c2701f362..b8166f672 100644 --- a/apps/launcher/graphicspage.hpp +++ b/apps/launcher/graphicspage.hpp @@ -30,6 +30,7 @@ class GraphicsPage : public QWidget public: GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent = 0); + bool setupOgre(); void writeConfig(); public slots: @@ -62,8 +63,6 @@ private: QStringList getAvailableResolutions(Ogre::RenderSystem *renderer); void createPages(); - void setupConfig(); - void setupOgre(); void readConfig(); }; diff --git a/apps/launcher/main.cpp b/apps/launcher/main.cpp index cbc1c4da3..4ae09f844 100644 --- a/apps/launcher/main.cpp +++ b/apps/launcher/main.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include "maindialog.hpp" @@ -32,9 +31,13 @@ int main(int argc, char *argv[]) QDir::setCurrent(dir.absolutePath()); MainDialog mainWin; - mainWin.show(); - return app.exec(); + if (mainWin.setup()) { + mainWin.show(); + return app.exec(); + } + + return 0; } diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 63ea96b6f..f7dafd3af 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -7,28 +7,6 @@ MainDialog::MainDialog() { - // Create the settings manager and load default settings file - const std::string localdefault = mCfgMgr.getLocalPath().string() + "/settings-default.cfg"; - const std::string globaldefault = mCfgMgr.getGlobalPath().string() + "/settings-default.cfg"; - - // prefer local - if (boost::filesystem::exists(localdefault)) - mSettings.loadDefault(localdefault); - else if (boost::filesystem::exists(globaldefault)) - mSettings.loadDefault(globaldefault); - else - throw std::runtime_error ("No default settings file found! Make sure the file \"settings-default.cfg\" was properly installed."); - - // load user settings if they exist, otherwise just load the default settings as user settings - const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg"; - if (boost::filesystem::exists(settingspath)) - mSettings.loadUser(settingspath); - else if (boost::filesystem::exists(localdefault)) - mSettings.loadUser(localdefault); - else if (boost::filesystem::exists(globaldefault)) - mSettings.loadUser(globaldefault); - - QWidget *centralWidget = new QWidget(this); setCentralWidget(centralWidget); @@ -72,22 +50,22 @@ MainDialog::MainDialog() // Install the stylesheet font QFile file; QFontDatabase fontDatabase; - + const QStringList fonts = fontDatabase.families(); - + // Check if the font is installed if (!fonts.contains("EB Garamond")) { - + QString font = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); file.setFileName(font); - + if (!file.exists()) { - font = QString::fromStdString((mCfgMgr.getLocalPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); + font = QString::fromStdString((mCfgMgr.getLocalPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); } - + fontDatabase.addApplicationFont(font); } - + // Load the stylesheet QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string()); file.setFileName(config); @@ -101,7 +79,6 @@ MainDialog::MainDialog() qApp->setStyleSheet(styleSheet); file.close(); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(close())); connect(buttonBox, SIGNAL(accepted()), this, SLOT(play())); @@ -172,6 +149,53 @@ void MainDialog::createPages() } + +bool MainDialog::setup() +{ + // Create the settings manager and load default settings file + const std::string localdefault = (mCfgMgr.getLocalPath() / "settings-default.cfg").string(); + const std::string globaldefault = (mCfgMgr.getGlobalPath() / "settings-default.cfg").string(); + + // prefer local + if (boost::filesystem::exists(localdefault)) { + mSettings.loadDefault(localdefault); + } else if (boost::filesystem::exists(globaldefault)) { + mSettings.loadDefault(globaldefault); + } else { + QMessageBox msgBox; + msgBox.setWindowTitle("Error reading OpenMW configuration file"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.setText(tr("
Could not find %0

\ + The problem may be due to an incomplete installation of OpenMW.
\ + Reinstalling OpenMW may resolve the problem.").arg(QString::fromStdString(globaldefault))); + msgBox.exec(); + return false; + } + + // load user settings if they exist, otherwise just load the default settings as user settings + const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); + + if (boost::filesystem::exists(settingspath)) + mSettings.loadUser(settingspath); + else if (boost::filesystem::exists(localdefault)) + mSettings.loadUser(localdefault); + else if (boost::filesystem::exists(globaldefault)) + mSettings.loadUser(globaldefault); + + // Setup the Graphics page + if (!mGraphicsPage->setupOgre()) { + return false; + } + + // Setup the Data Files page + if (!mDataFilesPage->setupDataFiles()) { + return false; + } + + return true; +} + void MainDialog::profileChanged(int index) { // Just to be sure, should always have a selection @@ -204,7 +228,7 @@ void MainDialog::closeEvent(QCloseEvent *event) mGraphicsPage->writeConfig(); // Save user settings - const std::string settingspath = mCfgMgr.getUserPath().string() + "/settings.cfg"; + const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); mSettings.saveUser(settingspath); event->accept(); @@ -216,6 +240,10 @@ void MainDialog::play() mDataFilesPage->writeConfig(); mGraphicsPage->writeConfig(); + // Save user settings + const std::string settingspath = (mCfgMgr.getUserPath() / "settings.cfg").string(); + mSettings.saveUser(settingspath); + #ifdef Q_WS_WIN QString game = "./openmw.exe"; QFile file(game); @@ -248,7 +276,7 @@ void MainDialog::play() if (!info.isExecutable()) { QMessageBox msgBox; msgBox.setWindowTitle("Error starting OpenMW"); - msgBox.setIcon(QMessageBox::Critical); + msgBox.setIcon(QMessageBox::Warning); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setText(tr("
Could not start OpenMW

\ The OpenMW application is not executable.
\ @@ -272,6 +300,7 @@ void MainDialog::play() return; } else { - close(); + qApp->quit(); } } + diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 59c6cbd2d..683cd58c2 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -28,6 +28,7 @@ public slots: void changePage(QListWidgetItem *current, QListWidgetItem *previous); void play(); void profileChanged(int index); + bool setup(); private: void createIcons(); diff --git a/apps/launcher/naturalsort.cpp b/apps/launcher/naturalsort.cpp index 648038ed7..50d1e77de 100644 --- a/apps/launcher/naturalsort.cpp +++ b/apps/launcher/naturalsort.cpp @@ -93,3 +93,13 @@ bool naturalSortLessThanCI( const QString &left, const QString &right ) { return (naturalCompare( left, right, Qt::CaseInsensitive ) < 0); } + +bool naturalSortGreaterThanCS( const QString &left, const QString &right ) +{ + return (naturalCompare( left, right, Qt::CaseSensitive ) > 0); +} + +bool naturalSortGreaterThanCI( const QString &left, const QString &right ) +{ + return (naturalCompare( left, right, Qt::CaseInsensitive ) > 0); +} diff --git a/apps/launcher/naturalsort.hpp b/apps/launcher/naturalsort.hpp index 2d314396f..59271547a 100644 --- a/apps/launcher/naturalsort.hpp +++ b/apps/launcher/naturalsort.hpp @@ -5,5 +5,7 @@ bool naturalSortLessThanCS( const QString &left, const QString &right ); bool naturalSortLessThanCI( const QString &left, const QString &right ); +bool naturalSortGreaterThanCS( const QString &left, const QString &right ); +bool naturalSortGreaterThanCI( const QString &left, const QString &right ); -#endif \ No newline at end of file +#endif diff --git a/apps/launcher/pluginsview.cpp b/apps/launcher/pluginsview.cpp index 27af45c56..26cf337fb 100644 --- a/apps/launcher/pluginsview.cpp +++ b/apps/launcher/pluginsview.cpp @@ -1,4 +1,3 @@ -#include #include #include "pluginsview.hpp" diff --git a/apps/launcher/resources/images/openmw-header.png b/apps/launcher/resources/images/openmw-header.png index 98c0cbe6f..82223e7fa 100644 Binary files a/apps/launcher/resources/images/openmw-header.png and b/apps/launcher/resources/images/openmw-header.png differ diff --git a/apps/launcher/resources/images/playpage-background.png b/apps/launcher/resources/images/playpage-background.png index 0116adc0f..ccd36d029 100644 Binary files a/apps/launcher/resources/images/playpage-background.png and b/apps/launcher/resources/images/playpage-background.png differ diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 045f504a7..02fe0b72c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -15,42 +15,43 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects - renderinginterface localmap occlusionquery terrain terrainmaterial water shadows shaderhelper + renderinginterface localmap occlusionquery terrain terrainmaterial water shadows compositors ) add_openmw_dir (mwinput - inputmanager + inputmanagerimp + mouselookevent ) add_openmw_dir (mwgui - text_input widgets race class birth review window_manager console dialogue + text_input widgets race class birth review windowmanagerimp console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow - confirmationdialog alchemywindow referenceinterface spellwindow + confirmationdialog alchemywindow referenceinterface spellwindow mainmenu ) add_openmw_dir (mwdialogue - dialoguemanager journal journalentry quest topic + dialoguemanagerimp journalimp journalentry quest topic ) add_openmw_dir (mwscript - locals scriptmanager compilercontext interpretercontext cellextensions miscextensions + locals scriptmanagerimp compilercontext interpretercontext cellextensions miscextensions guiextensions soundextensions skyextensions statsextensions containerextensions aiextensions controlextensions extensions globalscripts ref dialogueextensions - animationextensions + animationextensions transformationextensions consoleextensions userextensions ) add_openmw_dir (mwsound - soundmanager openal_output audiere_decoder mpgsnd_decoder ffmpeg_decoder + soundmanagerimp openal_output audiere_decoder mpgsnd_decoder ffmpeg_decoder ) add_openmw_dir (mwworld - refdata world physicssystem scene globals class action nullaction actionteleport + refdata worldimp physicssystem scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors cells localscripts customdata weather inventorystore ptr actionopen actionread - actionequip timestamp actionalchemy + actionequip timestamp actionalchemy cellstore actionapply ) add_openmw_dir (mwclass @@ -59,12 +60,13 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanager stat creaturestats magiceffects movement actors drawstate spells - activespells + mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells + activespells npcstats ) add_openmw_dir (mwbase - environment + environment world scriptmanager dialoguemanager journal soundmanager mechanicsmanager + inputmanager windowmanager ) # Main executable @@ -79,7 +81,6 @@ ENDIF(WIN32) ENDIF(OGRE_STATIC) add_executable(openmw ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} - ${COMPONENT_FILES} ${OPENMW_FILES} ${GAME} ${GAME_HEADER} ${APPLE_BUNDLE_RESOURCES} @@ -101,6 +102,8 @@ target_link_libraries(openmw ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} ${MYGUI_PLATFORM_LIBRARIES} + "shiny" + "shiny.OgrePlatform" components ) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e192b1f88..75835120f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,56 +1,38 @@ #include "engine.hpp" #include "components/esm/loadcell.hpp" -#include - -#include -#include - #include #include #include -#include -#include - -#include -#include #include -#include -#include #include -#include #include #include #include -#include "mwinput/inputmanager.hpp" +#include "mwinput/inputmanagerimp.hpp" -#include "mwgui/window_manager.hpp" +#include "mwgui/windowmanagerimp.hpp" #include "mwgui/cursorreplace.hpp" -#include "mwscript/scriptmanager.hpp" -#include "mwscript/compilercontext.hpp" -#include "mwscript/interpretercontext.hpp" +#include "mwscript/scriptmanagerimp.hpp" #include "mwscript/extensions.hpp" -#include "mwscript/globalscripts.hpp" -#include "mwsound/soundmanager.hpp" +#include "mwsound/soundmanagerimp.hpp" -#include "mwworld/world.hpp" #include "mwworld/class.hpp" #include "mwworld/player.hpp" +#include "mwworld/worldimp.hpp" #include "mwclass/classes.hpp" -#include "mwdialogue/dialoguemanager.hpp" -#include "mwdialogue/journal.hpp" +#include "mwdialogue/dialoguemanagerimp.hpp" +#include "mwdialogue/journalimp.hpp" -#include "mwmechanics/mechanicsmanager.hpp" - -#include "mwbase/environment.hpp" +#include "mwmechanics/mechanicsmanagerimp.hpp" void OMW::Engine::executeLocalScripts() @@ -74,11 +56,8 @@ void OMW::Engine::executeLocalScripts() localScripts.setIgnore (MWWorld::Ptr()); } -void OMW::Engine::setAnimationVerbose(bool animverbose){ - if(animverbose){ - NifOgre::NIFLoader::getSingletonPtr()->setOutputAnimFiles(true); - NifOgre::NIFLoader::getSingletonPtr()->setVerbosePath(mCfgMgr.getLogPath().string()); - } +void OMW::Engine::setAnimationVerbose(bool animverbose) +{ } bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) @@ -126,9 +105,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); - MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), - window->getTriangleCount(), - window->getBatchCount()); + unsigned int tri, batch; + MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); + MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); } @@ -150,6 +129,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mCompileAll (false) , mScriptContext (0) , mFSStrict (false) + , mScriptConsoleMode (false) , mCfgMgr(configurationManager) { std::srand ( std::time(NULL) ); @@ -310,7 +290,6 @@ void OMW::Engine::go() } mOgre->configure( mCfgMgr.getLogPath().string(), - mCfgMgr.getPluginsConfigPath().string(), renderSystem, false); @@ -348,7 +327,8 @@ void OMW::Engine::go() MWScript::registerExtensions (mExtensions); mEnvironment.setWindowManager (new MWGui::WindowManager( - mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"))); + mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/"), + mScriptConsoleMode)); // Create sound system mEnvironment.setSoundManager (new MWSound::SoundManager(mUseSound)); @@ -410,6 +390,9 @@ void OMW::Engine::go() << std::endl; } + if (!mStartupScript.empty()) + MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript); + // Start the main rendering loop mOgre->start(); @@ -512,3 +495,13 @@ void OMW::Engine::setFallbackValues(std::map fallbackMa { mFallbackMap = fallbackMap; } + +void OMW::Engine::setScriptConsoleMode (bool enabled) +{ + mScriptConsoleMode = enabled; +} + +void OMW::Engine::setStartupScript (const std::string& path) +{ + mStartupScript = path; +} diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index cf1ef3b9c..57402c91e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -1,10 +1,6 @@ #ifndef ENGINE_H #define ENGINE_H -#include - -#include - #include #include @@ -77,6 +73,8 @@ namespace OMW bool mCompileAll; std::string mFocusName; std::map mFallbackMap; + bool mScriptConsoleMode; + std::string mStartupScript; Compiler::Extensions mExtensions; Compiler::Context *mScriptContext; @@ -162,6 +160,12 @@ namespace OMW void setFallbackValues(std::map map); + /// Enable console-only script functionality + void setScriptConsoleMode (bool enabled); + + /// Set path for a script that is run on startup in the console. + void setStartupScript (const std::string& path); + private: Files::ConfigurationManager& mCfgMgr; }; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 68aa12fb3..0ca9dd6d9 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -1,13 +1,5 @@ #include -#include -#include - -#include - -#include -#include -#include #include #include "engine.hpp" @@ -16,15 +8,10 @@ #include #include -# if !defined(_DEBUG) -# include -# include -# endif - // For OutputDebugString #include // makes __argc and __argv available on windows -#include +#include #endif @@ -52,8 +39,6 @@ inline boost::filesystem::path lexical_cast mMap; }; @@ -139,12 +124,20 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("script-verbose", bpo::value()->implicit_value(true) ->default_value(false), "verbose script output") - ("new-game", bpo::value()->implicit_value(true) - ->default_value(false), "activate char gen/new game mechanics") - ("script-all", bpo::value()->implicit_value(true) ->default_value(false), "compile all scripts (excluding dialogue scripts) at startup") + ("script-console", bpo::value()->implicit_value(true) + ->default_value(false), "enable console-only script functionality") + + ("script-run", bpo::value()->default_value(""), + "select a file that is executed in the console on startup\n\n" + "Note: The file contains a list of script lines, but not a complete scripts. " + "That means no begin/end and no variable declarations.") + + ("new-game", bpo::value()->implicit_value(true) + ->default_value(false), "activate char gen/new game mechanics") + ("fs-strict", bpo::value()->implicit_value(true) ->default_value(false), "strict file system handling (no case folding)") @@ -264,6 +257,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setCompileAll(variables["script-all"].as()); engine.setAnimationVerbose(variables["anim-verbose"].as()); engine.setFallbackValues(variables["fallback"].as().mMap); + engine.setScriptConsoleMode (variables["script-console"].as()); + engine.setStartupScript (variables["script-run"].as()); return true; } diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp new file mode 100644 index 000000000..ccffc6b21 --- /dev/null +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -0,0 +1,46 @@ +#ifndef GAME_MWBASE_DIALOGUEMANAGER_H +#define GAME_MWBASE_DIALOGUEMANAGER_H + +#include + +namespace MWWorld +{ + class Ptr; +} + +namespace MWBase +{ + /// \brief Interface for dialogue manager (implemented in MWDialogue) + class DialogueManager + { + DialogueManager (const DialogueManager&); + ///< not implemented + + DialogueManager& operator= (const DialogueManager&); + ///< not implemented + + public: + + DialogueManager() {} + + virtual ~DialogueManager() {} + + virtual void startDialogue (const MWWorld::Ptr& actor) = 0; + + virtual void addTopic (const std::string& topic) = 0; + + virtual void askQuestion (const std::string& question,int choice) = 0; + + virtual void goodbye() = 0; + + ///get the faction of the actor you are talking with + virtual std::string getFaction() const = 0; + + //calbacks for the GUI + virtual void keywordSelected (const std::string& keyword) = 0; + virtual void goodbyeSelected() = 0; + virtual void questionAnswered (const std::string& answer) = 0; + }; +} + +#endif diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 792e240f4..9aaa5af85 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -3,18 +3,14 @@ #include -#include "../mwinput/inputmanager.hpp" - -#include "../mwscript/scriptmanager.hpp" - -#include "../mwsound/soundmanager.hpp" - -#include "../mwworld/world.hpp" - -#include "../mwdialogue/dialoguemanager.hpp" -#include "../mwdialogue/journal.hpp" - -#include "../mwmechanics/mechanicsmanager.hpp" +#include "world.hpp" +#include "scriptmanager.hpp" +#include "dialoguemanager.hpp" +#include "journal.hpp" +#include "soundmanager.hpp" +#include "mechanicsmanager.hpp" +#include "inputmanager.hpp" +#include "windowmanager.hpp" MWBase::Environment *MWBase::Environment::sThis = 0; @@ -32,42 +28,42 @@ MWBase::Environment::~Environment() sThis = 0; } -void MWBase::Environment::setWorld (MWWorld::World *world) +void MWBase::Environment::setWorld (World *world) { mWorld = world; } -void MWBase::Environment::setSoundManager (MWSound::SoundManager *soundManager) +void MWBase::Environment::setSoundManager (SoundManager *soundManager) { mSoundManager = soundManager; } -void MWBase::Environment::setScriptManager (MWScript::ScriptManager *scriptManager) +void MWBase::Environment::setScriptManager (ScriptManager *scriptManager) { mScriptManager = scriptManager; } -void MWBase::Environment::setWindowManager (MWGui::WindowManager *windowManager) +void MWBase::Environment::setWindowManager (WindowManager *windowManager) { mWindowManager = windowManager; } -void MWBase::Environment::setMechanicsManager (MWMechanics::MechanicsManager *mechanicsManager) +void MWBase::Environment::setMechanicsManager (MechanicsManager *mechanicsManager) { mMechanicsManager = mechanicsManager; } -void MWBase::Environment::setDialogueManager (MWDialogue::DialogueManager *dialogueManager) +void MWBase::Environment::setDialogueManager (DialogueManager *dialogueManager) { mDialogueManager = dialogueManager; } -void MWBase::Environment::setJournal (MWDialogue::Journal *journal) +void MWBase::Environment::setJournal (Journal *journal) { mJournal = journal; } -void MWBase::Environment::setInputManager (MWInput::MWInputManager *inputManager) +void MWBase::Environment::setInputManager (InputManager *inputManager) { mInputManager = inputManager; } @@ -77,49 +73,49 @@ void MWBase::Environment::setFrameDuration (float duration) mFrameDuration = duration; } -MWWorld::World *MWBase::Environment::getWorld() const +MWBase::World *MWBase::Environment::getWorld() const { assert (mWorld); return mWorld; } -MWSound::SoundManager *MWBase::Environment::getSoundManager() const +MWBase::SoundManager *MWBase::Environment::getSoundManager() const { assert (mSoundManager); return mSoundManager; } -MWScript::ScriptManager *MWBase::Environment::getScriptManager() const +MWBase::ScriptManager *MWBase::Environment::getScriptManager() const { assert (mScriptManager); return mScriptManager; } -MWGui::WindowManager *MWBase::Environment::getWindowManager() const +MWBase::WindowManager *MWBase::Environment::getWindowManager() const { assert (mWindowManager); return mWindowManager; } -MWMechanics::MechanicsManager *MWBase::Environment::getMechanicsManager() const +MWBase::MechanicsManager *MWBase::Environment::getMechanicsManager() const { assert (mMechanicsManager); return mMechanicsManager; } -MWDialogue::DialogueManager *MWBase::Environment::getDialogueManager() const +MWBase::DialogueManager *MWBase::Environment::getDialogueManager() const { assert (mDialogueManager); return mDialogueManager; } -MWDialogue::Journal *MWBase::Environment::getJournal() const +MWBase::Journal *MWBase::Environment::getJournal() const { assert (mJournal); return mJournal; } -MWInput::MWInputManager *MWBase::Environment::getInputManager() const +MWBase::InputManager *MWBase::Environment::getInputManager() const { assert (mInputManager); return mInputManager; @@ -150,6 +146,9 @@ void MWBase::Environment::cleanup() delete mScriptManager; mScriptManager = 0; + delete mWindowManager; + mWindowManager = 0; + delete mWorld; mWorld = 0; } diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index 521beee0a..a80e7ef87 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -1,44 +1,17 @@ #ifndef GAME_BASE_INVIRONMENT_H #define GAME_BASE_INVIRONMENT_H -namespace MWSound -{ - class SoundManager; -} - -namespace MWScript -{ - class ScriptManager; -} - -namespace MWGui -{ - class WindowManager; -} - -namespace MWMechanics -{ - class MechanicsManager; -} - -namespace MWDialogue -{ - class DialogueManager; - class Journal; -} - -namespace MWInput -{ - struct MWInputManager; -} - -namespace MWWorld -{ - class World; -} - namespace MWBase { + class World; + class ScriptManager; + class DialogueManager; + class Journal; + class SoundManager; + class MechanicsManager; + class InputManager; + class WindowManager; + /// \brief Central hub for mw-subsystems /// /// This class allows each mw-subsystem to access any others subsystem's top-level manager class. @@ -49,14 +22,14 @@ namespace MWBase { static Environment *sThis; - MWWorld::World *mWorld; - MWSound::SoundManager *mSoundManager; - MWScript::ScriptManager *mScriptManager; - MWGui::WindowManager *mWindowManager; - MWMechanics::MechanicsManager *mMechanicsManager; - MWDialogue::DialogueManager *mDialogueManager; - MWDialogue::Journal *mJournal; - MWInput::MWInputManager *mInputManager; + World *mWorld; + SoundManager *mSoundManager; + ScriptManager *mScriptManager; + WindowManager *mWindowManager; + MechanicsManager *mMechanicsManager; + DialogueManager *mDialogueManager; + Journal *mJournal; + InputManager *mInputManager; float mFrameDuration; Environment (const Environment&); @@ -71,40 +44,40 @@ namespace MWBase ~Environment(); - void setWorld (MWWorld::World *world); + void setWorld (World *world); - void setSoundManager (MWSound::SoundManager *soundManager); + void setSoundManager (SoundManager *soundManager); - void setScriptManager (MWScript::ScriptManager *scriptManager); + void setScriptManager (MWBase::ScriptManager *scriptManager); - void setWindowManager (MWGui::WindowManager *windowManager); + void setWindowManager (WindowManager *windowManager); - void setMechanicsManager (MWMechanics::MechanicsManager *mechanicsManager); + void setMechanicsManager (MechanicsManager *mechanicsManager); - void setDialogueManager (MWDialogue::DialogueManager *dialogueManager); + void setDialogueManager (DialogueManager *dialogueManager); - void setJournal (MWDialogue::Journal *journal); + void setJournal (Journal *journal); - void setInputManager (MWInput::MWInputManager *inputManager); + void setInputManager (InputManager *inputManager); void setFrameDuration (float duration); ///< Set length of current frame in seconds. - MWWorld::World *getWorld() const; + World *getWorld() const; - MWSound::SoundManager *getSoundManager() const; + SoundManager *getSoundManager() const; - MWScript::ScriptManager *getScriptManager() const; + ScriptManager *getScriptManager() const; - MWGui::WindowManager *getWindowManager() const; + WindowManager *getWindowManager() const; - MWMechanics::MechanicsManager *getMechanicsManager() const; + MechanicsManager *getMechanicsManager() const; - MWDialogue::DialogueManager *getDialogueManager() const; + DialogueManager *getDialogueManager() const; - MWDialogue::Journal *getJournal() const; + Journal *getJournal() const; - MWInput::MWInputManager *getInputManager() const; + InputManager *getInputManager() const; float getFrameDuration() const; diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp new file mode 100644 index 000000000..d865bfb0e --- /dev/null +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -0,0 +1,37 @@ +#ifndef GAME_MWBASE_INPUTMANAGER_H +#define GAME_MWBASE_INPUTMANAGER_H + +#include + +#include + +namespace MWBase +{ + /// \brief Interface for input manager (implemented in MWInput) + class InputManager + { + InputManager (const InputManager&); + ///< not implemented + + InputManager& operator= (const InputManager&); + ///< not implemented + + public: + + InputManager() {} + + virtual ~InputManager() {} + + virtual void update() = 0; + + virtual void changeInputMode(bool guiMode) = 0; + + virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + + virtual void setDragDrop(bool dragDrop) = 0; + + virtual void toggleControlSwitch (const std::string& sw, bool value) = 0; + }; +} + +#endif diff --git a/apps/openmw/mwbase/journal.hpp b/apps/openmw/mwbase/journal.hpp new file mode 100644 index 000000000..b3dfea45b --- /dev/null +++ b/apps/openmw/mwbase/journal.hpp @@ -0,0 +1,73 @@ +#ifndef GAME_MWBASE_JOURNAL_H +#define GAME_MWBASE_JOURNAL_H + +#include +#include +#include + +#include "../mwdialogue/journalentry.hpp" +#include "../mwdialogue/topic.hpp" +#include "../mwdialogue/quest.hpp" + +namespace MWBase +{ + /// \brief Interface for the player's journal (implemented in MWDialogue) + class Journal + { + Journal (const Journal&); + ///< not implemented + + Journal& operator= (const Journal&); + ///< not implemented + + public: + + typedef std::deque TEntryContainer; + typedef TEntryContainer::const_iterator TEntryIter; + typedef std::map TQuestContainer; // topc, quest + typedef TQuestContainer::const_iterator TQuestIter; + typedef std::map TTopicContainer; // topic-id, topic-content + typedef TTopicContainer::const_iterator TTopicIter; + + public: + + Journal() {} + + virtual ~Journal() {} + + virtual void addEntry (const std::string& id, int index) = 0; + ///< Add a journal entry. + + virtual void setJournalIndex (const std::string& id, int index) = 0; + ///< Set the journal index without adding an entry. + + virtual int getJournalIndex (const std::string& id) const = 0; + ///< Get the journal index. + + virtual void addTopic (const std::string& topicId, const std::string& infoId) = 0; + + virtual TEntryIter begin() const = 0; + ///< Iterator pointing to the begin of the main journal. + /// + /// \note Iterators to main journal entries will never become invalid. + + virtual TEntryIter end() const = 0; + ///< Iterator pointing past the end of the main journal. + + virtual TQuestIter questBegin() const = 0; + ///< Iterator pointing to the first quest (sorted by topic ID) + + virtual TQuestIter questEnd() const = 0; + ///< Iterator pointing past the last quest. + + virtual TTopicIter topicBegin() const = 0; + ///< Iterator pointing to the first topic (sorted by topic ID) + /// + /// \note The topic ID is identical with the user-visible topic string. + + virtual TTopicIter topicEnd() const = 0; + ///< Iterator pointing past the last topic. + }; +} + +#endif diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp new file mode 100644 index 000000000..c5f1847af --- /dev/null +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -0,0 +1,77 @@ +#ifndef GAME_MWBASE_MECHANICSMANAGER_H +#define GAME_MWBASE_MECHANICSMANAGER_H + +#include +#include + +namespace Ogre +{ + class Vector3; +} + +namespace ESM +{ + struct Class; +} + +namespace MWWorld +{ + class Ptr; + class CellStore; +} + +namespace MWBase +{ + /// \brief Interface for game mechanics manager (implemented in MWMechanics) + class MechanicsManager + { + MechanicsManager (const MechanicsManager&); + ///< not implemented + + MechanicsManager& operator= (const MechanicsManager&); + ///< not implemented + + public: + + MechanicsManager() {} + + virtual ~MechanicsManager() {} + + virtual void addActor (const MWWorld::Ptr& ptr) = 0; + ///< Register an actor for stats management + + virtual void removeActor (const MWWorld::Ptr& ptr) = 0; + ///< Deregister an actor for stats management + + virtual void dropActors (const MWWorld::CellStore *cellStore) = 0; + ///< Deregister all actors in the given cell. + + virtual void watchActor (const MWWorld::Ptr& ptr) = 0; + ///< On each update look for changes in a previously registered actor and update the + /// GUI accordingly. + + virtual void update (std::vector >& movement, + float duration, bool paused) = 0; + ///< Update actor stats and store desired velocity vectors in \a movement + /// + /// \param paused In game type does not currently advance (this usually means some GUI + /// component is up). + + virtual void setPlayerName (const std::string& name) = 0; + ///< Set player name. + + virtual void setPlayerRace (const std::string& id, bool male) = 0; + ///< Set player race. + + virtual void setPlayerBirthsign (const std::string& id) = 0; + ///< Set player birthsign. + + virtual void setPlayerClass (const std::string& id) = 0; + ///< Set player class to stock class. + + virtual void setPlayerClass (const ESM::Class& class_) = 0; + ///< Set player class to custom class. + }; +} + +#endif diff --git a/apps/openmw/mwbase/scriptmanager.hpp b/apps/openmw/mwbase/scriptmanager.hpp new file mode 100644 index 000000000..ae146e064 --- /dev/null +++ b/apps/openmw/mwbase/scriptmanager.hpp @@ -0,0 +1,62 @@ +#ifndef GAME_MWBASE_SCRIPTMANAGER_H +#define GAME_MWBASE_SCRIPTMANAGER_H + +#include + +namespace Interpreter +{ + class Context; +} + +namespace Compiler +{ + class Locals; +} + +namespace MWScript +{ + class GlobalScripts; +} + +namespace MWBase +{ + /// \brief Interface for script manager (implemented in MWScript) + class ScriptManager + { + ScriptManager (const ScriptManager&); + ///< not implemented + + ScriptManager& operator= (const ScriptManager&); + ///< not implemented + + public: + + ScriptManager() {} + + virtual ~ScriptManager() {} + + virtual void run (const std::string& name, Interpreter::Context& interpreterContext) = 0; + ///< Run the script with the given name (compile first, if not compiled yet) + + virtual bool compile (const std::string& name) = 0; + ///< Compile script with the given namen + /// \return Success? + + virtual std::pair compileAll() = 0; + ///< Compile all scripts + /// \return count, success + + virtual Compiler::Locals& getLocals (const std::string& name) = 0; + ///< Return locals for script \a name. + + virtual MWScript::GlobalScripts& getGlobalScripts() = 0; + + virtual int getLocalIndex (const std::string& scriptId, const std::string& variable, + char type) = 0; + ///< Return index of the variable of the given name and type in the given script. Will + /// throw an exception, if there is no such script or variable or the type does not match. + + }; +} + +#endif diff --git a/apps/openmw/mwbase/soundmanager.hpp b/apps/openmw/mwbase/soundmanager.hpp new file mode 100644 index 000000000..dfc619bf9 --- /dev/null +++ b/apps/openmw/mwbase/soundmanager.hpp @@ -0,0 +1,129 @@ +#ifndef GAME_MWBASE_SOUNDMANAGER_H +#define GAME_MWBASE_SOUNDMANAGER_H + +#include + +#include + +#include + +#include "../mwworld/ptr.hpp" + +namespace Ogre +{ + class Vector3; +} + +namespace MWWorld +{ + class CellStore; +} + +namespace MWSound +{ + class Sound; +} + +namespace MWBase +{ + typedef boost::shared_ptr SoundPtr; + + /// \brief Interface for sound manager (implemented in MWSound) + class SoundManager + { + public: + + enum PlayMode { + Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ + Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ + Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ + Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position + * but do not keep it updated (the sound will not move with + * the object and will not stop when the object is deleted. */ + }; + + private: + + SoundManager (const SoundManager&); + ///< not implemented + + SoundManager& operator= (const SoundManager&); + ///< not implemented + + public: + + SoundManager() {} + + virtual ~SoundManager() {} + + virtual void processChangedSettings(const Settings::CategorySettingVector& settings) = 0; + + virtual void stopMusic() = 0; + ///< Stops music if it's playing + + virtual void streamMusic(const std::string& filename) = 0; + ///< Play a soundifle + /// \param filename name of a sound file in "Music/" in the data directory. + + virtual void startRandomTitle() = 0; + ///< Starts a random track from the current playlist + + virtual bool isMusicPlaying() = 0; + ///< Returns true if music is playing + + virtual void playPlaylist(const std::string &playlist) = 0; + ///< Start playing music from the selected folder + /// \param name of the folder that contains the playlist + + virtual void say(MWWorld::Ptr reference, const std::string& filename) = 0; + ///< Make an actor say some text. + /// \param filename name of a sound file in "Sound/" in the data directory. + + virtual void say(const std::string& filename) = 0; + ///< Say some text, without an actor ref + /// \param filename name of a sound file in "Sound/" in the data directory. + + virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const = 0; + ///< Is actor not speaking? + + virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()) = 0; + ///< Stop an actor speaking + + virtual SoundPtr playSound(const std::string& soundId, float volume, float pitch, + int mode=Play_Normal) = 0; + ///< Play a sound, independently of 3D-position + + virtual SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, + float volume, float pitch, int mode=Play_Normal) = 0; + ///< Play a sound from an object + + virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId) = 0; + ///< Stop the given object from playing the given sound, + + virtual void stopSound3D(MWWorld::Ptr reference) = 0; + ///< Stop the given object from playing all sounds. + + virtual void stopSound(const MWWorld::CellStore *cell) = 0; + ///< Stop all sounds for the given cell. + + virtual void stopSound(const std::string& soundId) = 0; + ///< Stop a non-3d looping sound + + virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const = 0; + ///< Is the given sound currently playing on the given object? + + virtual void updateObject(MWWorld::Ptr reference) = 0; + ///< Update the position of all sounds connected to the given object. + + virtual void update(float duration) = 0; + + virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir) = 0; + }; + + inline int operator|(SoundManager::PlayMode a, SoundManager::PlayMode b) + { return static_cast (a) | static_cast (b); } + inline int operator&(SoundManager::PlayMode a, SoundManager::PlayMode b) + { return static_cast (a) & static_cast (b); } +} + +#endif diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp new file mode 100644 index 000000000..931353a90 --- /dev/null +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -0,0 +1,210 @@ +#ifndef GAME_MWBASE_WINDOWMANAGER_H +#define GAME_MWBASE_WINDOWMANAGER_H + +#include +#include +#include + +#include + +#include "../mwmechanics/stat.hpp" + +#include "../mwgui/mode.hpp" + +namespace MyGUI +{ + class Gui; + class Widget; + class UString; +} + +namespace OEngine +{ + namespace GUI + { + class Layout; + } +} + +namespace ESM +{ + struct Class; +} + +namespace MWWorld +{ + class CellStore; + class Ptr; +} + +namespace MWGui +{ + class Console; + class SpellWindow; + class TradeWindow; + class ConfirmationDialog; + class CountDialog; + class ScrollWindow; + class BookWindow; + class InventoryWindow; + class ContainerWindow; + class DialogueWindow; +} + +namespace MWBase +{ + /// \brief Interface for widnow manager (implemented in MWGui) + class WindowManager + { + WindowManager (const WindowManager&); + ///< not implemented + + WindowManager& operator= (const WindowManager&); + ///< not implemented + + public: + + typedef std::vector SkillList; + + WindowManager() {} + + virtual ~WindowManager() {} + + /** + * Should be called each frame to update windows/gui elements. + * This could mean updating sizes of gui elements or opening + * new dialogs. + */ + virtual void update() = 0; + + virtual void pushGuiMode (MWGui::GuiMode mode) = 0; + virtual void popGuiMode() = 0; + + virtual void removeGuiMode (MWGui::GuiMode mode) = 0; + ///< can be anywhere in the stack + + virtual MWGui::GuiMode getMode() const = 0; + + virtual bool isGuiMode() const = 0; + + virtual void toggleVisible (MWGui::GuiWindow wnd) = 0; + + /// Disallow all inventory mode windows + virtual void disallowAll() = 0; + + /// Allow one or more windows + virtual void allow (MWGui::GuiWindow wnd) = 0; + + virtual bool isAllowed (MWGui::GuiWindow wnd) const = 0; + + /// \todo investigate, if we really need to expose every single lousy UI element to the outside world + virtual MWGui::DialogueWindow* getDialogueWindow() = 0; + virtual MWGui::ContainerWindow* getContainerWindow() = 0; + virtual MWGui::InventoryWindow* getInventoryWindow() = 0; + virtual MWGui::BookWindow* getBookWindow() = 0; + virtual MWGui::ScrollWindow* getScrollWindow() = 0; + virtual MWGui::CountDialog* getCountDialog() = 0; + virtual MWGui::ConfirmationDialog* getConfirmationDialog() = 0; + virtual MWGui::TradeWindow* getTradeWindow() = 0; + virtual MWGui::SpellWindow* getSpellWindow() = 0; + virtual MWGui::Console* getConsole() = 0; + + virtual MyGUI::Gui* getGui() const = 0; + + virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) = 0; + + /// Set value for the given ID. + virtual void setValue (const std::string& id, const MWMechanics::Stat& value) = 0; + virtual void setValue (int parSkill, const MWMechanics::Stat& value) = 0; + virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value) = 0; + virtual void setValue (const std::string& id, const std::string& value) = 0; + virtual void setValue (const std::string& id, int value) = 0; + + virtual void setPlayerClass (const ESM::Class &class_) = 0; + ///< set current class of player + + virtual void configureSkills (const SkillList& major, const SkillList& minor) = 0; + ///< configure skill groups, each set contains the skill ID for that group. + + virtual void setReputation (int reputation) = 0; + ///< set the current reputation value + + virtual void setBounty (int bounty) = 0; + ///< set the current bounty value + + virtual void updateSkillArea() = 0; + ///< update display of skills, factions, birth sign, reputation and bounty + + virtual void changeCell(MWWorld::CellStore* cell) = 0; + ///< change the active cell + + virtual void setPlayerPos(const float x, const float y) = 0; + ///< set player position in map space + + virtual void setPlayerDir(const float x, const float y) = 0; + ///< set player view direction in map space + + 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 getMousePosition(int &x, int &y) = 0; + virtual void getMousePosition(float &x, float &y) = 0; + virtual void setDragDrop(bool dragDrop) = 0; + virtual bool getWorldMouseOver() = 0; + + virtual void toggleFogOfWar() = 0; + + virtual void toggleFullHelp() = 0; + ///< show extra info in item tooltips (owner, script) + + virtual bool getFullHelp() const = 0; + + virtual void setInteriorMapTexture(const int x, const int y) = 0; + ///< set the index of the map texture that should be used (for interiors) + + /// sets the visibility of the hud health/magicka/stamina bars + virtual void setHMSVisibility(bool visible) = 0; + + /// sets the visibility of the hud minimap + virtual void setMinimapVisibility(bool visible) = 0; + virtual void setWeaponVisibility(bool visible) = 0; + virtual void setSpellVisibility(bool visible) = 0; + + virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; + virtual void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) = 0; + virtual void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) = 0; + virtual void unsetSelectedSpell() = 0; + virtual void unsetSelectedWeapon() = 0; + + virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; + ///< Hides dialog and schedules dialog to be deleted. + + virtual void messageBox (const std::string& message, const std::vector& buttons) = 0; + virtual int readPressedButton() = 0; + ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) + + virtual void onFrame (float frameDuration) = 0; + + /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. + virtual std::map > getPlayerSkillValues() = 0; + virtual std::map > getPlayerAttributeValues() = 0; + virtual SkillList getPlayerMinorSkills() = 0; + virtual SkillList getPlayerMajorSkills() = 0; + + /** + * Fetches a GMST string from the store, if there is no setting with the given + * ID or it is not a string the default string is returned. + * + * @param id Identifier for the GMST setting, e.g. "aName" + * @param default Default value if the GMST setting cannot be used. + */ + virtual const std::string &getGameSettingString(const std::string &id, const std::string &default_) = 0; + + virtual void processChangedSettings(const Settings::CategorySettingVector& changed) = 0; + + virtual void executeInConsole (const std::string& path) = 0; + }; +} + +#endif diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp new file mode 100644 index 000000000..8b809d399 --- /dev/null +++ b/apps/openmw/mwbase/world.hpp @@ -0,0 +1,254 @@ +#ifndef GAME_MWBASE_WORLD_H +#define GAME_MWBASE_WORLD_H + +#include + +#include + +#include "../mwworld/globals.hpp" + +namespace Ogre +{ + class Vector2; + class Vector3; +} + +namespace OEngine +{ + namespace Render + { + class Fader; + } +} + +namespace ESM +{ + class ESMReader; + struct Position; + struct Cell; + struct Class; + struct Potion; +} + +namespace ESMS +{ + struct ESMStore; +} + +namespace MWWorld +{ + class CellStore; + class Player; + class LocalScripts; + class Ptr; + class TimeStamp; +} + +namespace MWBase +{ + /// \brief Interface for the World (implemented in MWWorld) + class World + { + World (const World&); + ///< not implemented + + World& operator= (const World&); + ///< not implemented + + public: + + enum RenderMode + { + Render_CollisionDebug, + Render_Wireframe, + Render_Pathgrid, + Render_Compositors + }; + + World() {} + + virtual ~World() {} + + virtual OEngine::Render::Fader* getFader() = 0; + ///< \ŧodo remove this function. Rendering details should not be exposed. + + virtual MWWorld::CellStore *getExterior (int x, int y) = 0; + + virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; + + virtual void setWaterHeight(const float height) = 0; + + virtual void toggleWater() = 0; + + virtual void adjustSky() = 0; + + virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; + + virtual void setFallbackValues (const std::map& fallbackMap) = 0; + + virtual std::string getFallback (const std::string& key) const = 0; + + virtual std::string getFallback (const std::string& key, const std::string& def) const = 0; + + virtual MWWorld::Player& getPlayer() = 0; + + virtual const ESMS::ESMStore& getStore() const = 0; + + virtual ESM::ESMReader& getEsmReader() = 0; + + virtual MWWorld::LocalScripts& getLocalScripts() = 0; + + virtual bool hasCellChanged() const = 0; + ///< Has the player moved to a different cell, since the last frame? + + virtual bool isCellExterior() const = 0; + + virtual bool isCellQuasiExterior() const = 0; + + virtual Ogre::Vector2 getNorthVector (MWWorld::CellStore* cell) = 0; + ///< get north vector (OGRE coordinates) for given interior cell + + virtual MWWorld::Globals::Data& getGlobalVariable (const std::string& name) = 0; + + virtual MWWorld::Globals::Data getGlobalVariable (const std::string& name) const = 0; + + virtual char getGlobalVariableType (const std::string& name) const = 0; + ///< Return ' ', if there is no global variable with this name. + + virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; + ///< Return a pointer to a liveCellRef with the given name. + /// \param activeOnly do non search inactive cells. + + virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0; + ///< Return a pointer to a liveCellRef with the given Ogre handle. + + /// \todo enable reference in the OGRE scene + virtual void enable (const MWWorld::Ptr& ptr) = 0; + + /// \todo disable reference in the OGRE scene + virtual void disable (const MWWorld::Ptr& ptr) = 0; + + virtual void advanceTime (double hours) = 0; + ///< Advance in-game time. + + virtual void setHour (double hour) = 0; + ///< Set in-game time hour. + + virtual void setMonth (int month) = 0; + ///< Set in-game time month. + + virtual void setDay (int day) = 0; + ///< Set in-game time day. + + virtual MWWorld::TimeStamp getTimeStamp() const = 0; + ///< Return current in-game time stamp. + + virtual bool toggleSky() = 0; + ///< \return Resulting mode + + virtual void changeWeather(const std::string& region, unsigned int id) = 0; + + virtual int getCurrentWeather() const = 0; + + virtual int getMasserPhase() const = 0; + + virtual int getSecundaPhase() const = 0; + + virtual void setMoonColour (bool red) = 0; + + virtual float getTimeScaleFactor() const = 0; + + virtual void changeToInteriorCell (const std::string& cellName, + const ESM::Position& position) = 0; + ///< Move to interior cell. + + virtual void changeToExteriorCell (const ESM::Position& position) = 0; + ///< Move to exterior cell. + + virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0; + ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. + + virtual void markCellAsUnchanged() = 0; + + virtual std::string getFacedHandle() = 0; + ///< Return handle of the object the player is looking at + + virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; + + virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; + + virtual void + moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore &newCell, float x, float y, float z) = 0; + + virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0; + + virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; + + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) + const = 0; + ///< Convert cell numbers to position. + + virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const = 0; + ///< Convert position to cell numbers + + virtual void doPhysics (const std::vector >& actors, + float duration) = 0; + ///< Run physics simulation and modify \a world accordingly. + + virtual bool toggleCollisionMode() = 0; + ///< Toggle collision mode for player. If disabled player object should ignore + /// collisions and gravity. + ///< \return Resulting mode + + virtual bool toggleRenderMode (RenderMode mode) = 0; + ///< Toggle a render mode. + ///< \return Resulting mode + + virtual std::pair createRecord (const ESM::Potion& record) + = 0; + ///< Create a new recrod (of type potion) in the ESM store. + /// \return ID, pointer to created record + + virtual std::pair createRecord (const ESM::Class& record) + = 0; + ///< Create a new recrod (of type class) in the ESM store. + /// \return ID, pointer to created record + + virtual const ESM::Cell *createRecord (const ESM::Cell& record) = 0; + ///< Create a new recrod (of type cell) in the ESM store. + /// \return ID, pointer to created record + + virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, + int mode, int number = 1) = 0; + ///< Run animation for a MW-reference. Calls to this function for references that are + /// currently not in the rendered scene should be ignored. + /// + /// \param mode: 0 normal, 1 immediate start, 2 immediate loop + /// \param number How offen the animation should be run + + 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 rendered scene should be ignored. + + virtual void update (float duration) = 0; + + virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0; + ///< place an object into the gameworld at the specified cursor position + /// @param object + /// @param cursor X (relative 0-1) + /// @param cursor Y (relative 0-1) + /// @return true if the object was placed, or false if it was rejected because the position is too far away + + virtual void dropObjectOnGround (const MWWorld::Ptr& object) = 0; + + virtual bool canPlaceObject (float cursorX, float cursorY) = 0; + ///< @return true if it is possible to place on object at specified cursor location + + virtual void processChangedSettings (const Settings::CategorySettingVector& settings) = 0; + + virtual bool isSwimming(const MWWorld::Ptr &object) = 0; + virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) = 0; + }; +} + +#endif diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 505f61f4c..7b8cbd3da 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -3,48 +3,54 @@ #include -#include - -#include "../mwworld/ptr.hpp" -#include "../mwrender/objects.hpp" #include "../mwbase/environment.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld//cellstore.hpp" +#include "../mwworld/ptr.hpp" +#include "../mwworld/physicssystem.hpp" + +#include "../mwrender/objects.hpp" +#include "../mwrender/renderinginterface.hpp" + +#include "../mwgui/tooltips.hpp" namespace MWClass { void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Activator::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Activator::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Activator::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -52,7 +58,7 @@ namespace MWClass std::string Activator::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -67,7 +73,7 @@ namespace MWClass bool Activator::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -75,7 +81,7 @@ namespace MWClass MWGui::ToolTipInfo Activator::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -88,4 +94,13 @@ namespace MWClass return info; } + + MWWorld::Ptr + Activator::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.activators.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index 223dd0a36..4165fbc08 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -7,6 +7,10 @@ namespace MWClass { class Activator : public MWWorld::Class { + + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -28,6 +32,8 @@ namespace MWClass ///< Return name of the script attached to ptr static void registerSelf(); + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 6945f3c27..8a117af5d 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -3,57 +3,58 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/actionalchemy.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" #include "../mwrender/objects.hpp" +#include "../mwrender/renderinginterface.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/tooltips.hpp" -#include "../mwsound/soundmanager.hpp" - namespace MWClass { - void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const + void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Apparatus::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Apparatus::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -62,7 +63,7 @@ namespace MWClass boost::shared_ptr Apparatus::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -70,7 +71,7 @@ namespace MWClass std::string Apparatus::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -78,7 +79,7 @@ namespace MWClass int Apparatus::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -103,7 +104,7 @@ namespace MWClass std::string Apparatus::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -111,7 +112,7 @@ namespace MWClass bool Apparatus::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -119,7 +120,7 @@ namespace MWClass MWGui::ToolTipInfo Apparatus::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -147,4 +148,13 @@ namespace MWClass { return boost::shared_ptr(new MWWorld::ActionAlchemy()); } + + MWWorld::Ptr + Apparatus::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.appas.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index f33f92e2c..7045f62d6 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -7,6 +7,10 @@ namespace MWClass { class Apparatus : public MWWorld::Class { + + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -48,6 +52,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 83c0120c7..c48d7ff4d 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -5,56 +5,59 @@ #include #include -#include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/world.hpp" - -#include "../mwbase/environment.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" #include "../mwrender/objects.hpp" +#include "../mwrender/renderinginterface.hpp" -#include "../mwgui/window_manager.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwgui/tooltips.hpp" namespace MWClass { void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Armor::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + + std::string Armor::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Armor::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -63,7 +66,7 @@ namespace MWClass boost::shared_ptr Armor::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -76,7 +79,7 @@ namespace MWClass int Armor::getItemMaxHealth (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.health; @@ -84,7 +87,7 @@ namespace MWClass std::string Armor::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -92,7 +95,7 @@ namespace MWClass std::pair, bool> Armor::getEquipmentSlots (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots; @@ -126,7 +129,7 @@ namespace MWClass int Armor::getEquipmentSkill (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); std::string typeGmst; @@ -164,7 +167,7 @@ namespace MWClass int Armor::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -201,7 +204,7 @@ namespace MWClass std::string Armor::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -209,7 +212,7 @@ namespace MWClass bool Armor::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -217,7 +220,7 @@ namespace MWClass MWGui::ToolTipInfo Armor::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -260,7 +263,7 @@ namespace MWClass std::string Armor::getEnchantment (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->enchant; @@ -272,4 +275,13 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); } + + MWWorld::Ptr + Armor::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.armors.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index a63806162..51c0ea21c 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -7,6 +7,9 @@ namespace MWClass { class Armor : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -66,6 +69,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index a107d9b21..1e187342d 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -3,55 +3,57 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actionread.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" #include "../mwrender/objects.hpp" +#include "../mwrender/renderinginterface.hpp" -#include "../mwgui/window_manager.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwgui/tooltips.hpp" namespace MWClass { void Book::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Book::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Book::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Book::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -66,7 +68,7 @@ namespace MWClass std::string Book::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -74,7 +76,7 @@ namespace MWClass int Book::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -99,7 +101,7 @@ namespace MWClass std::string Book::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -107,7 +109,7 @@ namespace MWClass bool Book::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -115,7 +117,7 @@ namespace MWClass MWGui::ToolTipInfo Book::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -143,7 +145,7 @@ namespace MWClass std::string Book::getEnchantment (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->enchant; @@ -154,4 +156,12 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionRead(ptr)); } + MWWorld::Ptr + Book::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.books.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index ee3aac8d8..acb1aac06 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -7,6 +7,9 @@ namespace MWClass { class Book : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -50,6 +53,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 11b515faf..597eb22fe 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -3,58 +3,59 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" #include "../mwgui/tooltips.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Clothing::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Clothing::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Clothing::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -63,7 +64,7 @@ namespace MWClass boost::shared_ptr Clothing::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -71,7 +72,7 @@ namespace MWClass std::string Clothing::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -79,7 +80,7 @@ namespace MWClass std::pair, bool> Clothing::getEquipmentSlots (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots; @@ -119,7 +120,7 @@ namespace MWClass int Clothing::getEquipmentSkill (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); if (ref->base->data.type==ESM::Clothing::Shoes) @@ -130,7 +131,7 @@ namespace MWClass int Clothing::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -145,7 +146,7 @@ namespace MWClass std::string Clothing::getUpSoundId (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); if (ref->base->data.type == 8) @@ -157,7 +158,7 @@ namespace MWClass std::string Clothing::getDownSoundId (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); if (ref->base->data.type == 8) @@ -169,7 +170,7 @@ namespace MWClass std::string Clothing::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -177,7 +178,7 @@ namespace MWClass bool Clothing::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -185,7 +186,7 @@ namespace MWClass MWGui::ToolTipInfo Clothing::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -213,7 +214,7 @@ namespace MWClass std::string Clothing::getEnchantment (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->enchant; @@ -225,4 +226,13 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); } + + MWWorld::Ptr + Clothing::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.clothes.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index aba317be0..f7801848f 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -7,6 +7,9 @@ namespace MWClass { class Clothing : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -59,6 +62,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 99a32fc32..ad6da90dd 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -3,23 +3,23 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/customdata.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/actionopen.hpp" +#include "../mwworld/physicssystem.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" -#include "../mwworld/actionopen.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace { @@ -53,32 +53,33 @@ namespace MWClass void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Container::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Container::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } boost::shared_ptr Container::activate (const MWWorld::Ptr& ptr, @@ -117,7 +118,7 @@ namespace MWClass std::string Container::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -133,7 +134,7 @@ namespace MWClass std::string Container::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -148,7 +149,7 @@ namespace MWClass bool Container::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -156,7 +157,7 @@ namespace MWClass MWGui::ToolTipInfo Container::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -182,7 +183,7 @@ namespace MWClass float Container::getCapacity (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->weight; @@ -205,4 +206,13 @@ namespace MWClass { ptr.getCellRef().lockLevel = 0; } + + MWWorld::Ptr + Container::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.containers.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 739c75c77..006e4bd22 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -9,6 +9,10 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; + + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -51,6 +55,8 @@ namespace MWClass ///< Unlock object static void registerSelf(); + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c9b43896b..a22c2d661 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -4,17 +4,21 @@ #include #include "../mwmechanics/creaturestats.hpp" -#include "../mwmechanics/mechanicsmanager.hpp" #include "../mwmechanics/magiceffects.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" #include "../mwworld/customdata.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/physicssystem.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwrender/renderinginterface.hpp" + +#include "../mwgui/tooltips.hpp" namespace { @@ -40,27 +44,27 @@ namespace MWClass { std::auto_ptr data (new CustomData); - ESMS::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = ptr.get(); // creature stats - data->mCreatureStats.mAttributes[0].set (ref->base->data.strength); - data->mCreatureStats.mAttributes[1].set (ref->base->data.intelligence); - data->mCreatureStats.mAttributes[2].set (ref->base->data.willpower); - data->mCreatureStats.mAttributes[3].set (ref->base->data.agility); - data->mCreatureStats.mAttributes[4].set (ref->base->data.speed); - data->mCreatureStats.mAttributes[5].set (ref->base->data.endurance); - data->mCreatureStats.mAttributes[6].set (ref->base->data.personality); - data->mCreatureStats.mAttributes[7].set (ref->base->data.luck); - data->mCreatureStats.mDynamic[0].set (ref->base->data.health); - data->mCreatureStats.mDynamic[1].set (ref->base->data.mana); - data->mCreatureStats.mDynamic[2].set (ref->base->data.fatigue); + data->mCreatureStats.getAttribute(0).set (ref->base->data.strength); + data->mCreatureStats.getAttribute(1).set (ref->base->data.intelligence); + data->mCreatureStats.getAttribute(2).set (ref->base->data.willpower); + data->mCreatureStats.getAttribute(3).set (ref->base->data.agility); + data->mCreatureStats.getAttribute(4).set (ref->base->data.speed); + data->mCreatureStats.getAttribute(5).set (ref->base->data.endurance); + data->mCreatureStats.getAttribute(6).set (ref->base->data.personality); + data->mCreatureStats.getAttribute(7).set (ref->base->data.luck); + data->mCreatureStats.getHealth().set (ref->base->data.health); + data->mCreatureStats.getMagicka().set (ref->base->data.mana); + data->mCreatureStats.getFatigue().set (ref->base->data.fatigue); - data->mCreatureStats.mLevel = ref->base->data.level; + data->mCreatureStats.setLevel(ref->base->data.level); - data->mCreatureStats.mHello = ref->base->AI.hello; - data->mCreatureStats.mFight = ref->base->AI.fight; - data->mCreatureStats.mFlee = ref->base->AI.flee; - data->mCreatureStats.mAlarm = ref->base->AI.alarm; + data->mCreatureStats.setHello(ref->base->AI.hello); + data->mCreatureStats.setFight(ref->base->AI.fight); + data->mCreatureStats.setFlee(ref->base->AI.flee); + data->mCreatureStats.setAlarm(ref->base->AI.alarm); // store ptr.getRefData().setCustomData (data.release()); @@ -69,7 +73,7 @@ namespace MWClass std::string Creature::getId (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->mId; @@ -83,21 +87,29 @@ namespace MWClass void Creature::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = + const std::string model = getModel(ptr); + if(!model.empty()){ + physics.insertActorPhysics(ptr, model); + } + MWBase::Environment::get().getMechanicsManager()->addActor (ptr); + } + + std::string Creature::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + assert (ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertActorPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - - MWBase::Environment::get().getMechanicsManager()->addActor (ptr); + return ""; } std::string Creature::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -126,7 +138,7 @@ namespace MWClass std::string Creature::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -148,7 +160,7 @@ namespace MWClass MWGui::ToolTipInfo Creature::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -165,7 +177,7 @@ namespace MWClass float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - return stats.mAttributes[0].getModified()*5; + return stats.getAttribute(0).getModified()*5; } float Creature::getEncumbrance (const MWWorld::Ptr& ptr) const @@ -174,13 +186,22 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - weight -= stats.mMagicEffects.get (MWMechanics::EffectKey (8)).mMagnitude; // feather + weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (8)).mMagnitude; // feather - weight += stats.mMagicEffects.get (MWMechanics::EffectKey (7)).mMagnitude; // burden + weight += stats.getMagicEffects().get (MWMechanics::EffectKey (7)).mMagnitude; // burden if (weight<0) weight = 0; return weight; } + + MWWorld::Ptr + Creature::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.creatures.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 237f54e82..4de877b31 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -1,7 +1,6 @@ #ifndef GAME_MWCLASS_CREATURE_H #define GAME_MWCLASS_CREATURE_H -#include "../mwworld/class.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwrender/actors.hpp" @@ -12,6 +11,9 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual std::string getId (const MWWorld::Ptr& ptr) const; @@ -55,6 +57,13 @@ namespace MWClass /// effects). Throws an exception, if the object can't hold other objects. static void registerSelf(); + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool + isActor() const { + return true; + } }; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 7041de1c6..3b283a9d1 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -3,56 +3,59 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/actionteleport.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Door::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Door::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + + std::string Door::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } + return ""; } std::string Door::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); if (ref->ref.teleport && !ref->ref.destCell.empty()) // TODO doors that lead to exteriors @@ -64,7 +67,7 @@ namespace MWClass boost::shared_ptr Door::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); const std::string &openSound = ref->base->openSound; @@ -93,18 +96,18 @@ namespace MWClass if (ref->ref.teleport) { // teleport door + /// \todo remove this if clause once ActionTeleport can also support other actors if (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()==actor) { // the player is using the door // The reason this is not 3D is that it would get interrupted when you teleport MWBase::Environment::get().getSoundManager()->playSound(openSound, 1.0, 1.0); return boost::shared_ptr ( - new MWWorld::ActionTeleportPlayer (ref->ref.destCell, ref->ref.doorDest)); + new MWWorld::ActionTeleport (ref->ref.destCell, ref->ref.doorDest)); } else { // another NPC or a creature is using the door - // TODO return action for teleporting other NPC/creature return boost::shared_ptr (new MWWorld::NullAction); } } @@ -134,7 +137,7 @@ namespace MWClass std::string Door::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -149,7 +152,7 @@ namespace MWClass bool Door::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -157,7 +160,7 @@ namespace MWClass MWGui::ToolTipInfo Door::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -205,4 +208,13 @@ namespace MWClass return info; } + + MWWorld::Ptr + Door::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.doors.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 63d1c1ab8..b0f86f12d 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -7,6 +7,9 @@ namespace MWClass { class Door : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -38,6 +41,8 @@ namespace MWClass ///< Return name of the script attached to ptr static void registerSelf(); + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 0c7fa7e69..8f9f8a315 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -3,54 +3,57 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Ingredient::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Ingredient::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + + std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } + return ""; } std::string Ingredient::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -59,7 +62,7 @@ namespace MWClass boost::shared_ptr Ingredient::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -67,7 +70,7 @@ namespace MWClass std::string Ingredient::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -75,7 +78,7 @@ namespace MWClass int Ingredient::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -100,7 +103,7 @@ namespace MWClass std::string Ingredient::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -108,7 +111,7 @@ namespace MWClass bool Ingredient::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -116,7 +119,7 @@ namespace MWClass MWGui::ToolTipInfo Ingredient::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -152,4 +155,13 @@ namespace MWClass return info; } + + MWWorld::Ptr + Ingredient::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.ingreds.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 4c45bd69c..1365c4a71 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -7,6 +7,9 @@ namespace MWClass { class Ingredient : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -44,6 +47,8 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 154033433..40ecf0a0f 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -3,32 +3,32 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/nullaction.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/tooltips.hpp" -#include "../mwsound/soundmanager.hpp" - #include "../mwrender/objects.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); - assert (ref->base != NULL); + const std::string &model = ref->base->model; MWRender::Objects& objects = renderingInterface.getObjects(); @@ -47,25 +47,36 @@ namespace MWClass void Light::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); - assert (ref->base != NULL); + const std::string &model = ref->base->model; - if(!model.empty()){ + if(!model.empty()) { physics.insertObjectPhysics(ptr, "meshes\\" + model); } - - if (!ref->base->sound.empty()) - { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, ref->base->sound, 1.0, 1.0, MWSound::Play_Loop); + if (!ref->base->sound.empty()) { + MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->base->sound, 1.0, 1.0, MWBase::SoundManager::Play_Loop); } } + std::string Light::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert (ref->base != NULL); + + const std::string &model = ref->base->model; + if (!model.empty()) { + return "meshes\\" + model; + } + return ""; + } + std::string Light::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); if (ref->base->model.empty()) @@ -77,13 +88,13 @@ namespace MWClass boost::shared_ptr Light::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); if (!(ref->base->data.flags & ESM::Light::Carry)) return boost::shared_ptr (new MWWorld::NullAction); - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -91,7 +102,7 @@ namespace MWClass std::string Light::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -99,7 +110,7 @@ namespace MWClass std::pair, bool> Light::getEquipmentSlots (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots; @@ -112,7 +123,7 @@ namespace MWClass int Light::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -138,7 +149,7 @@ namespace MWClass std::string Light::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -146,7 +157,7 @@ namespace MWClass bool Light::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -154,7 +165,7 @@ namespace MWClass MWGui::ToolTipInfo Light::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -184,4 +195,13 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); } + + MWWorld::Ptr + Light::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.lights.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 91193dfdc..640e1705b 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -7,6 +7,9 @@ namespace MWClass { class Light : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -52,6 +55,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 27e292bc0..8fdd95760 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -3,58 +3,59 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/world.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" + #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Lockpick::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - - const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); } - } + std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); + + const std::string &model = ref->base->model; + if (!model.empty()) { + return "meshes\\" + model; + } + return ""; + } std::string Lockpick::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -63,7 +64,7 @@ namespace MWClass boost::shared_ptr Lockpick::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -71,7 +72,7 @@ namespace MWClass std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -88,7 +89,7 @@ namespace MWClass int Lockpick::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -113,7 +114,7 @@ namespace MWClass std::string Lockpick::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -121,7 +122,7 @@ namespace MWClass bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -129,7 +130,7 @@ namespace MWClass MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -163,4 +164,13 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); } + + MWWorld::Ptr + Lockpick::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.lockpicks.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 26aab584c..0961b55b2 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -7,6 +7,9 @@ namespace MWClass { class Lockpick : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -52,6 +55,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index d8e0553b9..2cd0f63a1 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -5,20 +5,21 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" +#include "../mwworld/manualref.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" #include @@ -26,37 +27,38 @@ namespace MWClass { void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Miscellaneous::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -65,7 +67,7 @@ namespace MWClass boost::shared_ptr Miscellaneous::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -73,7 +75,7 @@ namespace MWClass std::string Miscellaneous::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -81,7 +83,7 @@ namespace MWClass int Miscellaneous::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -96,7 +98,7 @@ namespace MWClass std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); if (ref->base->name == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) @@ -108,7 +110,7 @@ namespace MWClass std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); if (ref->base->name == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) @@ -120,7 +122,7 @@ namespace MWClass std::string Miscellaneous::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -128,7 +130,7 @@ namespace MWClass bool Miscellaneous::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -136,7 +138,7 @@ namespace MWClass MWGui::ToolTipInfo Miscellaneous::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -181,4 +183,39 @@ namespace MWClass return info; } + + MWWorld::Ptr + Miscellaneous::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::Ptr newPtr; + + const ESMS::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + if (MWWorld::Class::get(ptr).getName(ptr) == store.gameSettings.search("sGold")->str) { + int goldAmount = ptr.getRefData().getCount(); + + std::string base = "Gold_001"; + if (goldAmount >= 100) + base = "Gold_100"; + else if (goldAmount >= 25) + base = "Gold_025"; + else if (goldAmount >= 10) + base = "Gold_010"; + else if (goldAmount >= 5) + base = "Gold_005"; + + // Really, I have no idea why moving ref out of conditional + // scope causes list::push_back throwing std::bad_alloc + MWWorld::ManualRef newRef(store, base); + MWWorld::LiveCellRef *ref = + newRef.getPtr().get(); + newPtr = MWWorld::Ptr(&cell.miscItems.insert(*ref), &cell); + } else { + MWWorld::LiveCellRef *ref = + ptr.get(); + newPtr = MWWorld::Ptr(&cell.miscItems.insert(*ref), &cell); + } + return newPtr; + } } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 46b5b9662..a5a79a8f6 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -7,9 +7,12 @@ namespace MWClass { class Miscellaneous : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; @@ -44,6 +47,8 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index f30e164f9..94c98ba42 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -9,20 +9,25 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/movement.hpp" -#include "../mwmechanics/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/customdata.hpp" +#include "../mwworld/physicssystem.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwrender/actors.hpp" +#include "../mwrender/renderinginterface.hpp" -#include "../mwbase/environment.hpp" +#include "../mwgui/tooltips.hpp" namespace { @@ -53,7 +58,7 @@ namespace MWClass { std::auto_ptr data (new CustomData); - ESMS::LiveCellRef *ref = ptr.get(); + MWWorld::LiveCellRef *ref = ptr.get(); // NPC stats if (!ref->base->faction.empty()) @@ -62,11 +67,11 @@ namespace MWClass boost::algorithm::to_lower(faction); if(ref->base->npdt52.gold != -10) { - data->mNpcStats.mFactionRank[faction] = (int)ref->base->npdt52.rank; + data->mNpcStats.getFactionRanks()[faction] = (int)ref->base->npdt52.rank; } else { - data->mNpcStats.mFactionRank[faction] = (int)ref->base->npdt12.rank; + data->mNpcStats.getFactionRanks()[faction] = (int)ref->base->npdt12.rank; } } @@ -74,31 +79,31 @@ namespace MWClass if(ref->base->npdt52.gold != -10) { for (int i=0; i<27; ++i) - data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]); + data->mNpcStats.getSkill (i).setBase (ref->base->npdt52.skills[i]); - data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength); - data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence); - data->mCreatureStats.mAttributes[2].set (ref->base->npdt52.willpower); - data->mCreatureStats.mAttributes[3].set (ref->base->npdt52.agility); - data->mCreatureStats.mAttributes[4].set (ref->base->npdt52.speed); - data->mCreatureStats.mAttributes[5].set (ref->base->npdt52.endurance); - data->mCreatureStats.mAttributes[6].set (ref->base->npdt52.personality); - data->mCreatureStats.mAttributes[7].set (ref->base->npdt52.luck); - data->mCreatureStats.mDynamic[0].set (ref->base->npdt52.health); - data->mCreatureStats.mDynamic[1].set (ref->base->npdt52.mana); - data->mCreatureStats.mDynamic[2].set (ref->base->npdt52.fatigue); + data->mCreatureStats.getAttribute(0).set (ref->base->npdt52.strength); + data->mCreatureStats.getAttribute(1).set (ref->base->npdt52.intelligence); + data->mCreatureStats.getAttribute(2).set (ref->base->npdt52.willpower); + data->mCreatureStats.getAttribute(3).set (ref->base->npdt52.agility); + data->mCreatureStats.getAttribute(4).set (ref->base->npdt52.speed); + data->mCreatureStats.getAttribute(5).set (ref->base->npdt52.endurance); + data->mCreatureStats.getAttribute(6).set (ref->base->npdt52.personality); + data->mCreatureStats.getAttribute(7).set (ref->base->npdt52.luck); + data->mCreatureStats.getHealth().set (ref->base->npdt52.health); + data->mCreatureStats.getMagicka().set (ref->base->npdt52.mana); + data->mCreatureStats.getFatigue().set (ref->base->npdt52.fatigue); - data->mCreatureStats.mLevel = ref->base->npdt52.level; + data->mCreatureStats.setLevel(ref->base->npdt52.level); } else { /// \todo do something with npdt12 maybe:p } - data->mCreatureStats.mHello = ref->base->AI.hello; - data->mCreatureStats.mFight = ref->base->AI.fight; - data->mCreatureStats.mFlee = ref->base->AI.flee; - data->mCreatureStats.mAlarm = ref->base->AI.alarm; + data->mCreatureStats.setHello(ref->base->AI.hello); + data->mCreatureStats.setFight(ref->base->AI.fight); + data->mCreatureStats.setFlee(ref->base->AI.flee); + data->mCreatureStats.setAlarm(ref->base->AI.alarm); // store ptr.getRefData().setCustomData (data.release()); @@ -107,7 +112,7 @@ namespace MWClass std::string Npc::getId (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->mId; @@ -120,25 +125,34 @@ namespace MWClass void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = + physics.insertActorPhysics(ptr, getModel(ptr)); + MWBase::Environment::get().getMechanicsManager()->addActor(ptr); + } + + std::string Npc::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = ptr.get(); + assert(ref->base != NULL); - assert (ref->base != NULL); std::string headID = ref->base->head; - std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); - bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; + int end = headID.find_last_of("head_") - 4; + std::string bodyRaceID = headID.substr(0, end); - std::string smodel = "meshes\\base_anim.nif"; - if(beast) - smodel = "meshes\\base_animkna.nif"; - physics.insertActorPhysics(ptr, smodel); - - MWBase::Environment::get().getMechanicsManager()->addActor (ptr); + std::string model = "meshes\\base_anim.nif"; + if (bodyRaceID == "b_n_khajiit_m_" || + bodyRaceID == "b_n_khajiit_f_" || + bodyRaceID == "b_n_argonian_m_" || + bodyRaceID == "b_n_argonian_f_") + { + model = "meshes\\base_animkna.nif"; + } + return model; } std::string Npc::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -182,7 +196,7 @@ namespace MWClass std::string Npc::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -196,12 +210,12 @@ namespace MWClass { case Run: - stats.mForceRun = force; + stats.setMovementFlag (MWMechanics::NpcStats::Flag_ForceRun, force); break; case Sneak: - stats.mForceSneak = force; + stats.setMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak, force); break; case Combat: @@ -218,17 +232,18 @@ namespace MWClass { case Run: - stats.mRun = set; + stats.setMovementFlag (MWMechanics::NpcStats::Flag_Run, set); break; case Sneak: - stats.mSneak = set; + stats.setMovementFlag (MWMechanics::NpcStats::Flag_Sneak, set); break; case Combat: - stats.mCombat = set; + // Combat stance ignored for now; need to be determined based on draw state instead of + // being maunally set. break; } } @@ -241,21 +256,21 @@ namespace MWClass { case Run: - if (!ignoreForce && stats.mForceRun) + if (!ignoreForce && stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun)) return true; - return stats.mRun; + return stats.getMovementFlag (MWMechanics::NpcStats::Flag_Run); case Sneak: - if (!ignoreForce && stats.mForceSneak) + if (!ignoreForce && stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)) return true; - return stats.mSneak; + return stats.getMovementFlag (MWMechanics::NpcStats::Flag_Sneak); case Combat: - return stats.mCombat; + return false; } return false; @@ -302,7 +317,7 @@ namespace MWClass MWGui::ToolTipInfo Npc::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -319,7 +334,7 @@ namespace MWClass float Npc::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - return stats.mAttributes[0].getModified()*5; + return stats.getAttribute(0).getModified()*5; } float Npc::getEncumbrance (const MWWorld::Ptr& ptr) const @@ -328,13 +343,50 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - weight -= stats.mMagicEffects.get (MWMechanics::EffectKey (8)).mMagnitude; // feather + weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (8)).mMagnitude; // feather - weight += stats.mMagicEffects.get (MWMechanics::EffectKey (7)).mMagnitude; // burden + weight += stats.getMagicEffects().get (MWMechanics::EffectKey (7)).mMagnitude; // burden if (weight<0) weight = 0; return weight; } + + bool Npc::apply (const MWWorld::Ptr& ptr, const std::string& id, + const MWWorld::Ptr& actor) const + { + MWMechanics::CreatureStats& stats = getCreatureStats (ptr); + + /// \todo consider instant effects + + return stats.getActiveSpells().addSpell (id); + } + + void Npc::skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const + { + MWMechanics::NpcStats& stats = getNpcStats (ptr); + + MWWorld::LiveCellRef *ref = ptr.get(); + + const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().classes.find ( + ref->base->cls); + + stats.useSkill (skill, *class_, usageType); + } + + void Npc::adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const + { + y = 0; + x = 0; + } + + MWWorld::Ptr + Npc::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.npcs.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 4cb733977..edb6ca40f 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -9,6 +9,9 @@ namespace MWClass { void ensureCustomData (const MWWorld::Ptr& ptr) const; + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual std::string getId (const MWWorld::Ptr& ptr) const; @@ -48,7 +51,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr - virtual void setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const; + virtual void setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. virtual void setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const; @@ -76,7 +79,25 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual bool apply (const MWWorld::Ptr& ptr, const std::string& id, + const MWWorld::Ptr& actor) const; + ///< Apply \a id on \a ptr. + /// \param actor Actor that is resposible for the ID being applied to \a ptr. + /// \return Any effect? + + virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const; + ///< Inform actor \a ptr that a skill use has succeeded. + + virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const; + static void registerSelf(); + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool + isActor() const { + return true; + } }; } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 157af01f5..6bff85553 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -3,56 +3,59 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/actionapply.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" +#include "../mwworld/player.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Potion::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Potion::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Potion::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -61,7 +64,7 @@ namespace MWClass boost::shared_ptr Potion::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -69,7 +72,7 @@ namespace MWClass std::string Potion::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -77,7 +80,7 @@ namespace MWClass int Potion::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -102,7 +105,7 @@ namespace MWClass std::string Potion::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -110,7 +113,7 @@ namespace MWClass bool Potion::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -118,7 +121,7 @@ namespace MWClass MWGui::ToolTipInfo Potion::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -143,4 +146,30 @@ namespace MWClass return info; } + + boost::shared_ptr Potion::use (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + ptr.getRefData().setCount (ptr.getRefData().getCount()-1); + + MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + boost::shared_ptr action ( + new MWWorld::ActionApply (actor, ref->base->mId)); + + action->setSound ("Drink"); + + return action; + } + + MWWorld::Ptr + Potion::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.potions.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 74779864a..d595f7e69 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -7,9 +7,12 @@ namespace MWClass { class Potion : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; @@ -34,6 +37,9 @@ namespace MWClass virtual int getValue (const MWWorld::Ptr& ptr) const; ///< Return trade value of the object. Throws an exception, if the object can't be traded. + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; + ///< Generate action for using via inventory menu + static void registerSelf(); virtual std::string getUpSoundId (const MWWorld::Ptr& ptr) const; @@ -44,6 +50,8 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 0b256d729..25aae445b 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -3,58 +3,59 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/world.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" + #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Probe::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - - const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); } - } + std::string Probe::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); + + const std::string &model = ref->base->model; + if (!model.empty()) { + return "meshes\\" + model; + } + return ""; + } std::string Probe::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -62,7 +63,7 @@ namespace MWClass boost::shared_ptr Probe::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -70,7 +71,7 @@ namespace MWClass std::string Probe::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -87,7 +88,7 @@ namespace MWClass int Probe::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -112,7 +113,7 @@ namespace MWClass std::string Probe::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -120,7 +121,7 @@ namespace MWClass bool Probe::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -128,7 +129,7 @@ namespace MWClass MWGui::ToolTipInfo Probe::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -162,4 +163,13 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); } + + MWWorld::Ptr + Probe::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.probes.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index 51b046fda..d9f90baf6 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -7,9 +7,12 @@ namespace MWClass { class Probe : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; @@ -52,6 +55,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 5666a95a5..ebba8c44e 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -3,55 +3,57 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwworld/world.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" + #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Repair::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Repair::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Repair::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -60,7 +62,7 @@ namespace MWClass boost::shared_ptr Repair::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -68,7 +70,7 @@ namespace MWClass std::string Repair::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -76,7 +78,7 @@ namespace MWClass int Repair::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -101,7 +103,7 @@ namespace MWClass std::string Repair::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -109,7 +111,7 @@ namespace MWClass bool Repair::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -117,7 +119,7 @@ namespace MWClass MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -143,4 +145,13 @@ namespace MWClass return info; } + + MWWorld::Ptr + Repair::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.repairs.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 1e935e154..c58e38f96 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -7,9 +7,12 @@ namespace MWClass { class Repair : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; @@ -44,6 +47,8 @@ namespace MWClass virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 4a4136816..e317b740c 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -4,39 +4,43 @@ #include #include "../mwworld/ptr.hpp" +#include "../mwworld/physicssystem.hpp" #include "../mwrender/objects.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Static::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), true); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Static::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); } } + + std::string Static::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); + + const std::string &model = ref->base->model; + if (!model.empty()) { + return "meshes\\" + model; + } + return ""; + } std::string Static::getName (const MWWorld::Ptr& ptr) const { @@ -49,4 +53,13 @@ namespace MWClass registerClass (typeid (ESM::Static).name(), instance); } + + MWWorld::Ptr + Static::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.statics.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/static.hpp b/apps/openmw/mwclass/static.hpp index cd1626c19..e36b3d142 100644 --- a/apps/openmw/mwclass/static.hpp +++ b/apps/openmw/mwclass/static.hpp @@ -7,9 +7,12 @@ namespace MWClass { class Static : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: - virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; + virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; ///< Add reference into a cell for rendering virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; @@ -19,6 +22,8 @@ namespace MWClass /// can return an empty string. static void registerSelf(); + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 482d618b0..2a9863cdf 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -3,58 +3,59 @@ #include -#include - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/world.hpp" +#include "../mwworld/cellstore.hpp" +#include "../mwworld/physicssystem.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwrender/renderinginterface.hpp" namespace MWClass { void Weapon::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - ESMS::LiveCellRef *ref = - ptr.get(); - - assert (ref->base != NULL); - const std::string &model = ref->base->model; - - if (!model.empty()) - { + const std::string model = getModel(ptr); + if (!model.empty()) { MWRender::Objects& objects = renderingInterface.getObjects(); objects.insertBegin(ptr, ptr.getRefData().isEnabled(), false); - objects.insertMesh(ptr, "meshes\\" + model); + objects.insertMesh(ptr, model); } } void Weapon::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const { - ESMS::LiveCellRef *ref = - ptr.get(); + const std::string model = getModel(ptr); + if(!model.empty()) { + physics.insertObjectPhysics(ptr, model); + } + } + std::string Weapon::getModel(const MWWorld::Ptr &ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + assert(ref->base != NULL); const std::string &model = ref->base->model; - assert (ref->base != NULL); - if(!model.empty()){ - physics.insertObjectPhysics(ptr, "meshes\\" + model); + if (!model.empty()) { + return "meshes\\" + model; } - + return ""; } std::string Weapon::getName (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->name; @@ -63,7 +64,7 @@ namespace MWClass boost::shared_ptr Weapon::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, getUpSoundId(ptr), 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); return boost::shared_ptr ( new MWWorld::ActionTake (ptr)); @@ -76,7 +77,7 @@ namespace MWClass int Weapon::getItemMaxHealth (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.health; @@ -84,7 +85,7 @@ namespace MWClass std::string Weapon::getScript (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->script; @@ -92,7 +93,7 @@ namespace MWClass std::pair, bool> Weapon::getEquipmentSlots (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); std::vector slots; @@ -116,7 +117,7 @@ namespace MWClass int Weapon::getEquipmentSkill (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); const int size = 12; @@ -146,7 +147,7 @@ namespace MWClass int Weapon::getValue (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->data.value; @@ -161,7 +162,7 @@ namespace MWClass std::string Weapon::getUpSoundId (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); int type = ref->base->data.type; @@ -207,7 +208,7 @@ namespace MWClass std::string Weapon::getDownSoundId (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); int type = ref->base->data.type; @@ -253,7 +254,7 @@ namespace MWClass std::string Weapon::getInventoryIcon (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->icon; @@ -261,7 +262,7 @@ namespace MWClass bool Weapon::hasToolTip (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return (ref->base->name != ""); @@ -269,7 +270,7 @@ namespace MWClass MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); MWGui::ToolTipInfo info; @@ -351,7 +352,7 @@ namespace MWClass std::string Weapon::getEnchantment (const MWWorld::Ptr& ptr) const { - ESMS::LiveCellRef *ref = + MWWorld::LiveCellRef *ref = ptr.get(); return ref->base->enchant; @@ -363,4 +364,13 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); } + + MWWorld::Ptr + Weapon::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return MWWorld::Ptr(&cell.weapons.insert(*ref), &cell); + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 92d703b4a..06cf88c5f 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -7,6 +7,9 @@ namespace MWClass { class Weapon : public MWWorld::Class { + virtual MWWorld::Ptr + copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const; + public: virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const; @@ -66,6 +69,7 @@ namespace MWClass const; ///< Generate action for using via inventory menu + virtual std::string getModel(const MWWorld::Ptr &ptr) const; }; } diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp similarity index 90% rename from apps/openmw/mwdialogue/dialoguemanager.cpp rename to apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 45e2c8cb3..acd786892 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -1,5 +1,5 @@ -#include "dialoguemanager.hpp" +#include "dialoguemanagerimp.hpp" #include #include @@ -10,34 +10,31 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/scriptmanager.hpp" +#include "../mwbase/journal.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/refdata.hpp" #include "../mwworld/player.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwinput/inputmanager.hpp" #include "../mwgui/dialogue.hpp" -#include "../mwgui/window_manager.hpp" - -#include "journal.hpp" #include -#include "../mwscript/extensions.hpp" -#include "../mwscript/scriptmanager.hpp" - #include #include #include #include #include +#include #include #include "../mwscript/compilercontext.hpp" #include "../mwscript/interpretercontext.hpp" -#include +#include "../mwscript/extensions.hpp" #include "../mwclass/npc.hpp" #include "../mwmechanics/npcstats.hpp" @@ -121,24 +118,24 @@ namespace } template - bool checkGlobal (char comp, const std::string& name, T value, MWWorld::World& world) + bool checkGlobal (char comp, const std::string& name, T value) { - switch (world.getGlobalVariableType (name)) + switch (MWBase::Environment::get().getWorld()->getGlobalVariableType (name)) { case 's': - return selectCompare (comp, world.getGlobalVariable (name).mShort, value); + return selectCompare (comp, MWBase::Environment::get().getWorld()->getGlobalVariable (name).mShort, value); case 'l': - return selectCompare (comp, world.getGlobalVariable (name).mLong, value); + return selectCompare (comp, MWBase::Environment::get().getWorld()->getGlobalVariable (name).mLong, value); case 'f': - return selectCompare (comp, world.getGlobalVariable (name).mFloat, value); + return selectCompare (comp, MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat, value); case ' ': - world.getGlobalVariable (name); // trigger exception + MWBase::Environment::get().getWorld()->getGlobalVariable (name); // trigger exception break; default: @@ -203,10 +200,10 @@ namespace MWDialogue MWMechanics::NpcStats PCstats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); MWMechanics::NpcStats NPCstats = MWWorld::Class::get(actor).getNpcStats(actor); int sameFaction = 0; - if(!NPCstats.mFactionRank.empty()) + if(!NPCstats.getFactionRanks().empty()) { - std::string NPCFaction = NPCstats.mFactionRank.begin()->first; - if(PCstats.mFactionRank.find(toLower(NPCFaction)) != PCstats.mFactionRank.end()) sameFaction = 1; + std::string NPCFaction = NPCstats.getFactionRanks().begin()->first; + if(PCstats.getFactionRanks().find(toLower(NPCFaction)) != PCstats.getFactionRanks().end()) sameFaction = 1; } if(!selectCompare(comp,sameFaction,select.i)) return false; } @@ -309,12 +306,12 @@ namespace MWDialogue if (select.type==ESM::VT_Short || select.type==ESM::VT_Int || select.type==ESM::VT_Long) { - if (!checkGlobal (comp, toLower (name), select.i, *MWBase::Environment::get().getWorld())) + if (!checkGlobal (comp, toLower (name), select.i)) return false; } else if (select.type==ESM::VT_Float) { - if (!checkGlobal (comp, toLower (name), select.f, *MWBase::Environment::get().getWorld())) + if (!checkGlobal (comp, toLower (name), select.f)) return false; } else @@ -392,7 +389,7 @@ namespace MWDialogue if(select.type==ESM::VT_Int) { - ESMS::LiveCellRef* npc = actor.get(); + MWWorld::LiveCellRef* npc = actor.get(); int isFaction = int(toLower(npc->base->faction) == toLower(name)); if(selectCompare(comp,!isFaction,select.i)) return false; @@ -409,7 +406,7 @@ namespace MWDialogue if(select.type==ESM::VT_Int) { - ESMS::LiveCellRef* npc = actor.get(); + MWWorld::LiveCellRef* npc = actor.get(); int isClass = int(toLower(npc->base->cls) == toLower(name)); if(selectCompare(comp,!isClass,select.i)) return false; @@ -426,7 +423,7 @@ namespace MWDialogue if(select.type==ESM::VT_Int) { - ESMS::LiveCellRef* npc = actor.get(); + MWWorld::LiveCellRef* npc = actor.get(); int isRace = int(toLower(npc->base->race) == toLower(name)); if(selectCompare(comp,!isRace,select.i)) return false; @@ -493,7 +490,7 @@ namespace MWDialogue if (isCreature) return false; - ESMS::LiveCellRef *cellRef = actor.get(); + MWWorld::LiveCellRef *cellRef = actor.get(); if (!cellRef) return false; @@ -508,7 +505,7 @@ namespace MWDialogue if (isCreature) return false; - ESMS::LiveCellRef *cellRef = actor.get(); + MWWorld::LiveCellRef *cellRef = actor.get(); if (!cellRef) return false; @@ -525,8 +522,8 @@ namespace MWDialogue //MWWorld::Class npcClass = MWWorld::Class::get(actor); MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor); - std::map::iterator it = stats.mFactionRank.find(toLower(info.npcFaction)); - if(it!=stats.mFactionRank.end()) + std::map::iterator it = stats.getFactionRanks().find(toLower(info.npcFaction)); + if(it!=stats.getFactionRanks().end()) { //check rank if(it->second < (int)info.data.rank) return false; @@ -542,8 +539,8 @@ namespace MWDialogue if(!info.pcFaction.empty()) { MWMechanics::NpcStats stats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - std::map::iterator it = stats.mFactionRank.find(toLower(info.pcFaction)); - if(it!=stats.mFactionRank.end()) + std::map::iterator it = stats.getFactionRanks().find(toLower(info.pcFaction)); + if(it!=stats.getFactionRanks().end()) { //check rank if(it->second < (int)info.data.PCrank) return false; @@ -558,7 +555,7 @@ namespace MWDialogue //check gender if (!isCreature) { - ESMS::LiveCellRef* npc = actor.get(); + MWWorld::LiveCellRef* npc = actor.get(); if(npc->base->flags&npc->base->Female) { if(static_cast (info.data.gender)==0) return false; @@ -591,7 +588,7 @@ namespace MWDialogue mIsInChoice = false; mCompilerContext.setExtensions (&extensions); mDialogueMap.clear(); - actorKnownTopics.clear(); + mActorKnownTopics.clear(); ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) { @@ -599,26 +596,26 @@ namespace MWDialogue } } - void DialogueManager::addTopic(std::string topic) + void DialogueManager::addTopic (const std::string& topic) { - knownTopics[toLower(topic)] = true; + mKnownTopics[toLower(topic)] = true; } - void DialogueManager::parseText(std::string text) + void DialogueManager::parseText (std::string text) { std::list::iterator it; - for(it = actorKnownTopics.begin();it != actorKnownTopics.end();++it) + for(it = mActorKnownTopics.begin();it != mActorKnownTopics.end();++it) { size_t pos = find_str_ci(text,*it,0); if(pos !=std::string::npos) { if(pos==0) { - knownTopics[*it] = true; + mKnownTopics[*it] = true; } else if(text.substr(pos -1,1) == " ") { - knownTopics[*it] = true; + mKnownTopics[*it] = true; } } } @@ -632,7 +629,7 @@ namespace MWDialogue mActor = actor; - actorKnownTopics.clear(); + mActorKnownTopics.clear(); //initialise the GUI MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Dialogue); @@ -706,7 +703,7 @@ namespace MWDialogue } return false; } - catch (const Compiler::SourceException& error) + catch (const Compiler::SourceException& /* error */) { // error has already been reported via error handler } @@ -742,7 +739,7 @@ namespace MWDialogue std::list keywordList; int choice = mChoice; mChoice = -1; - actorKnownTopics.clear(); + mActorKnownTopics.clear(); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); ESMS::RecListCaseT::MapType dialogueList = MWBase::Environment::get().getWorld()->getStore().dialogs.list; for(ESMS::RecListCaseT::MapType::iterator it = dialogueList.begin(); it!=dialogueList.end();it++) @@ -755,9 +752,9 @@ namespace MWDialogue { if (isMatching (mActor, *iter) && functionFilter(mActor,*iter,true)) { - actorKnownTopics.push_back(toLower(it->first)); + mActorKnownTopics.push_back(toLower(it->first)); //does the player know the topic? - if(knownTopics.find(toLower(it->first)) != knownTopics.end()) + if(mKnownTopics.find(toLower(it->first)) != mKnownTopics.end()) { keywordList.push_back(it->first); break; @@ -771,13 +768,13 @@ namespace MWDialogue int services = 0; if (mActor.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mActor.get(); + MWWorld::LiveCellRef* ref = mActor.get(); if (ref->base->hasAI) services = ref->base->AI.services; } else if (mActor.getTypeName() == typeid(ESM::Creature).name()) { - ESMS::LiveCellRef* ref = mActor.get(); + MWWorld::LiveCellRef* ref = mActor.get(); if (ref->base->hasAI) services = ref->base->AI.services; } @@ -804,7 +801,7 @@ namespace MWDialogue mChoice = choice; } - void DialogueManager::keywordSelected(std::string keyword) + void DialogueManager::keywordSelected (const std::string& keyword) { if(!mIsInChoice) { @@ -846,11 +843,11 @@ namespace MWDialogue MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); } - void DialogueManager::questionAnswered(std::string answere) + void DialogueManager::questionAnswered (const std::string& answer) { - if(mChoiceMap.find(answere) != mChoiceMap.end()) + if(mChoiceMap.find(answer) != mChoiceMap.end()) { - mChoice = mChoiceMap[answere]; + mChoice = mChoiceMap[answer]; std::vector::const_iterator iter; if(mDialogueMap.find(mLastTopic) != mDialogueMap.end()) @@ -882,13 +879,13 @@ namespace MWDialogue } } - void DialogueManager::printError(std::string error) + void DialogueManager::printError (std::string error) { MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->addText(error); } - void DialogueManager::askQuestion(std::string question, int choice) + void DialogueManager::askQuestion (const std::string& question, int choice) { MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->askQuestion(question); @@ -896,20 +893,20 @@ namespace MWDialogue mIsInChoice = true; } - std::string DialogueManager::getFaction() + std::string DialogueManager::getFaction() const { if (mActor.getTypeName() != typeid(ESM::NPC).name()) return ""; std::string factionID(""); MWMechanics::NpcStats stats = MWWorld::Class::get(mActor).getNpcStats(mActor); - if(stats.mFactionRank.empty()) + if(stats.getFactionRanks().empty()) { std::cout << "No faction for this actor!"; } else { - factionID = stats.mFactionRank.begin()->first; + factionID = stats.getFactionRanks().begin()->first; } return factionID; } diff --git a/apps/openmw/mwdialogue/dialoguemanager.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp similarity index 64% rename from apps/openmw/mwdialogue/dialoguemanager.hpp rename to apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 992175c0c..e3e9fd752 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -1,5 +1,7 @@ -#ifndef GAME_MMDIALOG_DIALOGUEMANAGER_H -#define GAME_MWDIALOG_DIALOGUEMANAGER_H +#ifndef GAME_MWDIALOG_DIALOGUEMANAGERIMP_H +#define GAME_MWDIALOG_DIALOGUEMANAGERIMP_H + +#include "../mwbase/dialoguemanager.hpp" #include @@ -9,11 +11,12 @@ #include #include "../mwworld/ptr.hpp" + #include namespace MWDialogue { - class DialogueManager + class DialogueManager : public MWBase::DialogueManager { bool isMatching (const MWWorld::Ptr& actor, const ESM::DialInfo::SelectStruct& select) const; @@ -26,8 +29,8 @@ namespace MWDialogue void updateTopics(); std::map mDialogueMap; - std::map knownTopics;// Those are the topics the player knows. - std::list actorKnownTopics; + std::map mKnownTopics;// Those are the topics the player knows. + std::list mActorKnownTopics; MWScript::CompilerContext mCompilerContext; std::ostream mErrorStream; @@ -50,21 +53,21 @@ namespace MWDialogue DialogueManager (const Compiler::Extensions& extensions); - void startDialogue (const MWWorld::Ptr& actor); + virtual void startDialogue (const MWWorld::Ptr& actor); - void addTopic(std::string topic); + virtual void addTopic (const std::string& topic); - void askQuestion(std::string question,int choice); + virtual void askQuestion (const std::string& question,int choice); - void goodbye(); + virtual void goodbye(); ///get the faction of the actor you are talking with - std::string getFaction(); + virtual std::string getFaction() const; //calbacks for the GUI - void keywordSelected(std::string keyword); - void goodbyeSelected(); - void questionAnswered(std::string answere); + virtual void keywordSelected (const std::string& keyword); + virtual void goodbyeSelected(); + virtual void questionAnswered (const std::string& answer); }; } diff --git a/apps/openmw/mwdialogue/journalentry.cpp b/apps/openmw/mwdialogue/journalentry.cpp index 4eb6b8001..9d58687e1 100644 --- a/apps/openmw/mwdialogue/journalentry.cpp +++ b/apps/openmw/mwdialogue/journalentry.cpp @@ -5,7 +5,8 @@ #include -#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWDialogue { @@ -27,16 +28,14 @@ namespace MWDialogue throw std::runtime_error ("unknown info ID " + mInfoId + " for topic " + mTopic); } - JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index, - const MWWorld::World& world) + JournalEntry JournalEntry::makeFromQuest (const std::string& topic, int index) { - return JournalEntry (topic, idFromIndex (topic, index, world)); + return JournalEntry (topic, idFromIndex (topic, index)); } - std::string JournalEntry::idFromIndex (const std::string& topic, int index, - const MWWorld::World& world) + std::string JournalEntry::idFromIndex (const std::string& topic, int index) { - const ESM::Dialogue *dialogue = world.getStore().dialogs.find (topic); + const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().dialogs.find (topic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) @@ -57,13 +56,12 @@ namespace MWDialogue : JournalEntry (topic, infoId), mDay (day), mMonth (month), mDayOfMonth (dayOfMonth) {} - StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index, - const MWWorld::World& world) + StampedJournalEntry StampedJournalEntry::makeFromQuest (const std::string& topic, int index) { - int day = world.getGlobalVariable ("dayspassed").mLong; - int month = world.getGlobalVariable ("day").mLong; - int dayOfMonth = world.getGlobalVariable ("month").mLong; + int day = MWBase::Environment::get().getWorld()->getGlobalVariable ("dayspassed").mLong; + int month = MWBase::Environment::get().getWorld()->getGlobalVariable ("day").mLong; + int dayOfMonth = MWBase::Environment::get().getWorld()->getGlobalVariable ("month").mLong; - return StampedJournalEntry (topic, idFromIndex (topic, index, world), day, month, dayOfMonth); + return StampedJournalEntry (topic, idFromIndex (topic, index), day, month, dayOfMonth); } } diff --git a/apps/openmw/mwdialogue/journalentry.hpp b/apps/openmw/mwdialogue/journalentry.hpp index 11b715630..3e8640185 100644 --- a/apps/openmw/mwdialogue/journalentry.hpp +++ b/apps/openmw/mwdialogue/journalentry.hpp @@ -1,5 +1,5 @@ -#ifndef GAME_MMDIALOGUE_JOURNALENTRY_H -#define GAME_MMDIALOGUE_JOURNALENTRY_H +#ifndef GAME_MWDIALOGUE_JOURNALENTRY_H +#define GAME_MWDIALOGUE_JOURNALENTRY_H #include @@ -8,11 +8,6 @@ namespace ESMS struct ESMStore; } -namespace MWWorld -{ - class World; -} - namespace MWDialogue { /// \brief A quest or dialogue entry @@ -27,11 +22,9 @@ namespace MWDialogue std::string getText (const ESMS::ESMStore& store) const; - static JournalEntry makeFromQuest (const std::string& topic, int index, - const MWWorld::World& world); + static JournalEntry makeFromQuest (const std::string& topic, int index); - static std::string idFromIndex (const std::string& topic, int index, - const MWWorld::World& world); + static std::string idFromIndex (const std::string& topic, int index); }; /// \biref A quest entry with a timestamp. @@ -46,8 +39,7 @@ namespace MWDialogue StampedJournalEntry (const std::string& topic, const std::string& infoId, int day, int month, int dayOfMonth); - static StampedJournalEntry makeFromQuest (const std::string& topic, int index, - const MWWorld::World& world); + static StampedJournalEntry makeFromQuest (const std::string& topic, int index); }; } diff --git a/apps/openmw/mwdialogue/journal.cpp b/apps/openmw/mwdialogue/journalimp.cpp similarity index 81% rename from apps/openmw/mwdialogue/journal.cpp rename to apps/openmw/mwdialogue/journalimp.cpp index eb828a76c..d626cd315 100644 --- a/apps/openmw/mwdialogue/journal.cpp +++ b/apps/openmw/mwdialogue/journalimp.cpp @@ -1,13 +1,14 @@ -#include "journal.hpp" +#include "journalimp.hpp" + +#include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" -#include "../mwgui/window_manager.hpp" #include "../mwgui/messagebox.hpp" -#include "../mwworld/world.hpp" - namespace MWDialogue { Quest& Journal::getQuest (const std::string& id) @@ -30,14 +31,13 @@ namespace MWDialogue void Journal::addEntry (const std::string& id, int index) { - StampedJournalEntry entry = - StampedJournalEntry::makeFromQuest (id, index, *MWBase::Environment::get().getWorld()); + StampedJournalEntry entry = StampedJournalEntry::makeFromQuest (id, index); mJournal.push_back (entry); Quest& quest = getQuest (id); - quest.addEntry (entry, *MWBase::Environment::get().getWorld()); // we are doing slicing on purpose here + quest.addEntry (entry); // we are doing slicing on purpose here std::vector empty; std::string notification = MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sJournalEntry")->str; @@ -48,7 +48,7 @@ namespace MWDialogue { Quest& quest = getQuest (id); - quest.setIndex (index, *MWBase::Environment::get().getWorld()); + quest.setIndex (index); } void Journal::addTopic (const std::string& topicId, const std::string& infoId) @@ -63,7 +63,7 @@ namespace MWDialogue iter = result.first; } - iter->second.addEntry (JournalEntry (topicId, infoId), *MWBase::Environment::get().getWorld()); + iter->second.addEntry (JournalEntry (topicId, infoId)); } int Journal::getJournalIndex (const std::string& id) const diff --git a/apps/openmw/mwdialogue/journal.hpp b/apps/openmw/mwdialogue/journalimp.hpp similarity index 50% rename from apps/openmw/mwdialogue/journal.hpp rename to apps/openmw/mwdialogue/journalimp.hpp index 62b9f4bed..7d71fd7d0 100644 --- a/apps/openmw/mwdialogue/journal.hpp +++ b/apps/openmw/mwdialogue/journalimp.hpp @@ -1,9 +1,7 @@ -#ifndef GAME_MMDIALOG_JOURNAL_H +#ifndef GAME_MWDIALOG_JOURNAL_H #define GAME_MWDIALOG_JOURNAL_H -#include -#include -#include +#include "../mwbase/journal.hpp" #include "journalentry.hpp" #include "quest.hpp" @@ -11,19 +9,8 @@ namespace MWDialogue { /// \brief The player's journal - class Journal + class Journal : public MWBase::Journal { - public: - - typedef std::deque TEntryContainer; - typedef TEntryContainer::const_iterator TEntryIter; - typedef std::map TQuestContainer; // topc, quest - typedef TQuestContainer::const_iterator TQuestIter; - typedef std::map TTopicContainer; // topic-id, topic-content - typedef TTopicContainer::const_iterator TTopicIter; - - private: - TEntryContainer mJournal; TQuestContainer mQuests; TTopicContainer mTopics; @@ -34,37 +21,37 @@ namespace MWDialogue Journal(); - void addEntry (const std::string& id, int index); + virtual void addEntry (const std::string& id, int index); ///< Add a journal entry. - void setJournalIndex (const std::string& id, int index); + virtual void setJournalIndex (const std::string& id, int index); ///< Set the journal index without adding an entry. - int getJournalIndex (const std::string& id) const; + virtual int getJournalIndex (const std::string& id) const; ///< Get the journal index. - void addTopic (const std::string& topicId, const std::string& infoId); + virtual void addTopic (const std::string& topicId, const std::string& infoId); - TEntryIter begin() const; + virtual TEntryIter begin() const; ///< Iterator pointing to the begin of the main journal. /// /// \note Iterators to main journal entries will never become invalid. - TEntryIter end() const; + virtual TEntryIter end() const; ///< Iterator pointing past the end of the main journal. - TQuestIter questBegin() const; + virtual TQuestIter questBegin() const; ///< Iterator pointing to the first quest (sorted by topic ID) - TQuestIter questEnd() const; + virtual TQuestIter questEnd() const; ///< Iterator pointing past the last quest. - TTopicIter topicBegin() const; + virtual TTopicIter topicBegin() const; ///< Iterator pointing to the first topic (sorted by topic ID) /// /// \note The topic ID is identical with the user-visible topic string. - TTopicIter topicEnd() const; + virtual TTopicIter topicEnd() const; ///< Iterator pointing past the last topic. }; } diff --git a/apps/openmw/mwdialogue/quest.cpp b/apps/openmw/mwdialogue/quest.cpp index 1f387e862..484c2c19c 100644 --- a/apps/openmw/mwdialogue/quest.cpp +++ b/apps/openmw/mwdialogue/quest.cpp @@ -3,7 +3,8 @@ #include -#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWDialogue { @@ -15,9 +16,9 @@ namespace MWDialogue : Topic (topic), mIndex (0), mFinished (false) {} - const std::string Quest::getName (const MWWorld::World& world) const + const std::string Quest::getName() const { - const ESM::Dialogue *dialogue = world.getStore().dialogs.find (mTopic); + const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().dialogs.find (mTopic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) @@ -32,9 +33,9 @@ namespace MWDialogue return mIndex; } - void Quest::setIndex (int index, const MWWorld::World& world) + void Quest::setIndex (int index) { - const ESM::Dialogue *dialogue = world.getStore().dialogs.find (mTopic); + const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().dialogs.find (mTopic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) @@ -58,11 +59,11 @@ namespace MWDialogue return mFinished; } - void Quest::addEntry (const JournalEntry& entry, const MWWorld::World& world) + void Quest::addEntry (const JournalEntry& entry) { int index = -1; - const ESM::Dialogue *dialogue = world.getStore().dialogs.find (entry.mTopic); + const ESM::Dialogue *dialogue = MWBase::Environment::get().getWorld()->getStore().dialogs.find (entry.mTopic); for (std::vector::const_iterator iter (dialogue->mInfo.begin()); iter!=dialogue->mInfo.end(); ++iter) @@ -75,7 +76,7 @@ namespace MWDialogue if (index==-1) throw std::runtime_error ("unknown journal entry for topic " + mTopic); - setIndex (index, world); + setIndex (index); for (TEntryIter iter (mEntries.begin()); iter!=mEntries.end(); ++iter) if (*iter==entry.mInfoId) diff --git a/apps/openmw/mwdialogue/quest.hpp b/apps/openmw/mwdialogue/quest.hpp index c162c03f4..3afa81fac 100644 --- a/apps/openmw/mwdialogue/quest.hpp +++ b/apps/openmw/mwdialogue/quest.hpp @@ -1,4 +1,4 @@ -#ifndef GAME_MMDIALOG_QUEST_H +#ifndef GAME_MWDIALOG_QUEST_H #define GAME_MWDIALOG_QUEST_H #include "topic.hpp" @@ -17,17 +17,17 @@ namespace MWDialogue Quest (const std::string& topic); - const std::string getName (const MWWorld::World& world) const; + const std::string getName() const; ///< May be an empty string int getIndex() const; - void setIndex (int index, const MWWorld::World& world); + void setIndex (int index); ///< Calling this function with a non-existant index while throw an exception. bool isFinished() const; - virtual void addEntry (const JournalEntry& entry, const MWWorld::World& world); + virtual void addEntry (const JournalEntry& entry); ///< Add entry and adjust index accordingly. /// /// \note Redundant entries are ignored, but the index is still adjusted. diff --git a/apps/openmw/mwdialogue/topic.cpp b/apps/openmw/mwdialogue/topic.cpp index 8f165d3c8..8c1dfafb8 100644 --- a/apps/openmw/mwdialogue/topic.cpp +++ b/apps/openmw/mwdialogue/topic.cpp @@ -3,8 +3,6 @@ #include -#include "../mwworld/world.hpp" - namespace MWDialogue { Topic::Topic() @@ -17,7 +15,7 @@ namespace MWDialogue Topic::~Topic() {} - void Topic::addEntry (const JournalEntry& entry, const MWWorld::World& world) + void Topic::addEntry (const JournalEntry& entry) { if (entry.mTopic!=mTopic) throw std::runtime_error ("topic does not match: " + mTopic); diff --git a/apps/openmw/mwdialogue/topic.hpp b/apps/openmw/mwdialogue/topic.hpp index c085f1ed9..566f60ab0 100644 --- a/apps/openmw/mwdialogue/topic.hpp +++ b/apps/openmw/mwdialogue/topic.hpp @@ -1,4 +1,4 @@ -#ifndef GAME_MMDIALOG_TOPIC_H +#ifndef GAME_MWDIALOG_TOPIC_H #define GAME_MWDIALOG_TOPIC_H #include @@ -6,11 +6,6 @@ #include "journalentry.hpp" -namespace MWWorld -{ - class World; -} - namespace MWDialogue { /// \brief Collection of seen responses for a topic @@ -34,7 +29,7 @@ namespace MWDialogue virtual ~Topic(); - virtual void addEntry (const JournalEntry& entry, const MWWorld::World& world); + virtual void addEntry (const JournalEntry& entry); ///< Add entry /// /// \note Redundant entries are ignored. diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 423678eed..5cf09b18a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -3,13 +3,13 @@ #include #include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/player.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/containerstore.hpp" -#include "../mwsound/soundmanager.hpp" - -#include "window_manager.hpp" namespace { @@ -26,8 +26,8 @@ namespace namespace MWGui { - AlchemyWindow::AlchemyWindow(WindowManager& parWindowManager) - : WindowBase("openmw_alchemy_window_layout.xml", parWindowManager) + AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_alchemy_window.layout", parWindowManager) , ContainerBase(0) { getWidget(mCreateButton, "CreateButton"); @@ -275,7 +275,7 @@ namespace MWGui for (MWWorld::ContainerStoreIterator it(store.begin(MWWorld::ContainerStore::Type_Apparatus)); it != store.end(); ++it) { - ESMS::LiveCellRef* ref = it->get(); + MWWorld::LiveCellRef* ref = it->get(); if (ref->base->data.type == ESM::Apparatus::Albemic && (bestAlbemic.isEmpty() || ref->base->data.quality > bestAlbemic.get()->base->data.quality)) bestAlbemic = *it; @@ -420,7 +420,7 @@ namespace MWGui continue; // add the effects of this ingredient to list of effects - ESMS::LiveCellRef* ref = ingredient->getUserData()->get(); + MWWorld::LiveCellRef* ref = ingredient->getUserData()->get(); for (int i=0; i<4; ++i) { if (ref->base->data.effectID[i] < 0) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index c01a18e41..53e7178d5 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -3,13 +3,14 @@ #include "window_base.hpp" #include "container.hpp" +#include "widgets.hpp" namespace MWGui { class AlchemyWindow : public WindowBase, public ContainerBase { public: - AlchemyWindow(WindowManager& parWindowManager); + AlchemyWindow(MWBase::WindowManager& parWindowManager); virtual void open(); diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 49f90d1a0..05a337cbc 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -1,29 +1,34 @@ #include "birth.hpp" -#include "window_manager.hpp" -#include "widgets.hpp" -#include "components/esm_store/store.hpp" #include #include +#include "components/esm_store/store.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "widgets.hpp" + using namespace MWGui; using namespace Widgets; -BirthDialog::BirthDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_birth_layout.xml", parWindowManager) +BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_birth.layout", parWindowManager) { // Centre dialog center(); - getWidget(spellArea, "SpellArea"); + getWidget(mSpellArea, "SpellArea"); - getWidget(birthImage, "BirthsignImage"); + getWidget(mBirthImage, "BirthsignImage"); - getWidget(birthList, "BirthsignList"); - birthList->setScrollVisible(true); - birthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - birthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - birthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + getWidget(mBirthList, "BirthsignList"); + mBirthList->setScrollVisible(true); + mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); @@ -68,14 +73,14 @@ void BirthDialog::open() void BirthDialog::setBirthId(const std::string &birthId) { - currentBirthId = birthId; - birthList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = birthList->getItemCount(); + mCurrentBirthId = birthId; + mBirthList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mBirthList->getItemCount(); for (size_t i = 0; i < count; ++i) { - if (boost::iequals(*birthList->getItemDataAt(i), birthId)) + if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) { - birthList->setIndexSelected(i); + mBirthList->setIndexSelected(i); break; } } @@ -100,11 +105,11 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - const std::string *birthId = birthList->getItemDataAt(_index); - if (boost::iequals(currentBirthId, *birthId)) + const std::string *birthId = mBirthList->getItemDataAt(_index); + if (boost::iequals(mCurrentBirthId, *birthId)) return; - currentBirthId = *birthId; + mCurrentBirthId = *birthId; updateSpells(); } @@ -112,9 +117,9 @@ void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) void BirthDialog::updateBirths() { - birthList->removeAllItems(); + mBirthList->removeAllItems(); - const ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); ESMS::RecListT::MapType::const_iterator it = store.birthSigns.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.birthSigns.list.end(); @@ -122,34 +127,34 @@ void BirthDialog::updateBirths() for (; it != end; ++it) { const ESM::BirthSign &birth = it->second; - birthList->addItem(birth.name, it->first); - if (boost::iequals(it->first, currentBirthId)) - birthList->setIndexSelected(index); + mBirthList->addItem(birth.name, it->first); + if (boost::iequals(it->first, mCurrentBirthId)) + mBirthList->setIndexSelected(index); ++index; } } void BirthDialog::updateSpells() { - for (std::vector::iterator it = spellItems.begin(); it != spellItems.end(); ++it) + for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } - spellItems.clear(); + mSpellItems.clear(); - if (currentBirthId.empty()) + if (mCurrentBirthId.empty()) return; MWSpellPtr spellWidget; const int lineHeight = 18; - MyGUI::IntCoord coord(0, 0, spellArea->getWidth(), 18); + MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), 18); - const ESMS::ESMStore &store = mWindowManager.getStore(); - const ESM::BirthSign *birth = store.birthSigns.find(currentBirthId); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::BirthSign *birth = store.birthSigns.find(mCurrentBirthId); std::string texturePath = std::string("textures\\") + birth->texture; fixTexturePath(texturePath); - birthImage->setImageTexture(texturePath); + mBirthImage->setImageTexture(texturePath); std::vector abilities, powers, spells; @@ -183,25 +188,25 @@ void BirthDialog::updateSpells() { if (!categories[category].spells.empty()) { - MyGUI::TextBox* label = spellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); + MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); label->setCaption(mWindowManager.getGameSettingString(categories[category].label, "")); - spellItems.push_back(label); + mSpellItems.push_back(label); coord.top += lineHeight; std::vector::const_iterator end = categories[category].spells.end(); for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) { const std::string &spellId = *it; - spellWidget = spellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); + spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); spellWidget->setWindowManager(&mWindowManager); spellWidget->setSpellId(spellId); - spellItems.push_back(spellWidget); + mSpellItems.push_back(spellWidget); coord.top += lineHeight; MyGUI::IntCoord spellCoord = coord; spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template? - spellWidget->createEffectWidgets(spellItems, spellArea, spellCoord, (category == 0) ? MWEffectList::EF_Constant : 0); + spellWidget->createEffectWidgets(mSpellItems, mSpellArea, spellCoord, (category == 0) ? MWEffectList::EF_Constant : 0); coord.top = spellCoord.top; ++i; diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index b5f7db774..92665081d 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -5,19 +5,18 @@ /* This file contains the dialog for choosing a birth sign. - Layout is defined by resources/mygui/openmw_chargen_race_layout.xml. + Layout is defined by resources/mygui/openmw_chargen_race.layout. */ namespace MWGui { + /// \todo remove using namespace MyGUI; - class WindowManager; - class BirthDialog : public WindowBase { public: - BirthDialog(WindowManager& parWindowManager); + BirthDialog(MWBase::WindowManager& parWindowManager); enum Gender { @@ -25,7 +24,7 @@ namespace MWGui GM_Female }; - const std::string &getBirthId() const { return currentBirthId; } + const std::string &getBirthId() const { return mCurrentBirthId; } void setBirthId(const std::string &raceId); void setNextButtonShow(bool shown); @@ -49,12 +48,12 @@ namespace MWGui void updateBirths(); void updateSpells(); - MyGUI::ListBox* birthList; - MyGUI::WidgetPtr spellArea; - MyGUI::ImageBox* birthImage; - std::vector spellItems; + MyGUI::ListBox* mBirthList; + MyGUI::WidgetPtr mSpellArea; + MyGUI::ImageBox* mBirthImage; + std::vector mSpellItems; - std::string currentBirthId; + std::string mCurrentBirthId; }; } #endif diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index a9dcd4555..57e59657a 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -3,17 +3,19 @@ #include #include "../mwbase/environment.hpp" -#include "../mwinput/inputmanager.hpp" -#include "../mwsound/soundmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/actiontake.hpp" +#include "../mwworld/player.hpp" #include "formatting.hpp" -#include "window_manager.hpp" using namespace MWGui; -BookWindow::BookWindow (WindowManager& parWindowManager) : - WindowBase("openmw_book_layout.xml", parWindowManager) +BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) : + WindowBase("openmw_book.layout", parWindowManager) { getWidget(mCloseButton, "CloseButton"); mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); @@ -55,8 +57,7 @@ void BookWindow::open (MWWorld::Ptr book) MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); - ESMS::LiveCellRef *ref = - mBook.get(); + MWWorld::LiveCellRef *ref = mBook.get(); BookTextParser parser; std::vector results = parser.split(ref->base->text, mLeftPage->getSize().width, mLeftPage->getSize().height); @@ -97,10 +98,10 @@ void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); MWWorld::ActionTake take(mBook); - take.execute(); + take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mWindowManager.removeGuiMode(GM_Book); } diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index 9ea011433..fedb783b2 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -10,7 +10,7 @@ namespace MWGui class BookWindow : public WindowBase { public: - BookWindow(WindowManager& parWindowManager); + BookWindow(MWBase::WindowManager& parWindowManager); void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); @@ -43,4 +43,3 @@ namespace MWGui } #endif - diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index c39e305dc..8c82b3e43 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -9,7 +9,8 @@ #include "mode.hpp" #include "../mwbase/environment.hpp" -#include "../mwsound/soundmanager.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" namespace { @@ -103,11 +104,19 @@ namespace {ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth} } } }; + + struct ClassPoint + { + const char *id; + // Specialization points to match, in order: Stealth, Combat, Magic + // Note: Order is taken from http://www.uesp.net/wiki/Morrowind:Class_Quiz + unsigned int points[3]; + }; } using namespace MWGui; -CharacterCreation::CharacterCreation(WindowManager* _wm) +CharacterCreation::CharacterCreation(MWBase::WindowManager* _wm) : mNameDialog(0) , mRaceDialog(0) , mClassChoiceDialog(0) @@ -178,8 +187,8 @@ void CharacterCreation::spawnDialog(const char id) switch (id) { case GM_Name: - if(mNameDialog) - mWM->removeDialog(mNameDialog); + mWM->removeDialog(mNameDialog); + mNameDialog = 0; mNameDialog = new TextInputDialog(*mWM); mNameDialog->setTextLabel(mWM->getGameSettingString("sName", "Name")); mNameDialog->setTextInput(mPlayerName); @@ -189,8 +198,8 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Race: - if (mRaceDialog) - mWM->removeDialog(mRaceDialog); + mWM->removeDialog(mRaceDialog); + mRaceDialog = 0; mRaceDialog = new RaceDialog(*mWM); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); @@ -200,16 +209,16 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Class: - if (mClassChoiceDialog) - mWM->removeDialog(mClassChoiceDialog); + mWM->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; mClassChoiceDialog = new ClassChoiceDialog(*mWM); mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); mClassChoiceDialog->open(); break; case GM_ClassPick: - if (mPickClassDialog) - mWM->removeDialog(mPickClassDialog); + mWM->removeDialog(mPickClassDialog); + mPickClassDialog = 0; mPickClassDialog = new PickClassDialog(*mWM); mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mPickClassDialog->setClassId(mPlayerClass.name); @@ -219,8 +228,8 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Birth: - if (mBirthSignDialog) - mWM->removeDialog(mBirthSignDialog); + mWM->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; mBirthSignDialog = new BirthDialog(*mWM); mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); @@ -229,8 +238,8 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_ClassCreate: - if (mCreateClassDialog) - mWM->removeDialog(mCreateClassDialog); + mWM->removeDialog(mCreateClassDialog); + mCreateClassDialog = 0; mCreateClassDialog = new CreateClassDialog(*mWM); mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); @@ -246,8 +255,8 @@ void CharacterCreation::spawnDialog(const char id) showClassQuestionDialog(); break; case GM_Review: - if (mReviewDialog) - mWM->removeDialog(mReviewDialog); + mWM->removeDialog(mReviewDialog); + mReviewDialog = 0; mReviewDialog = new ReviewDialog(*mWM); mReviewDialog->setPlayerName(mPlayerName); mReviewDialog->setRace(mPlayerRaceId); @@ -259,20 +268,20 @@ void CharacterCreation::spawnDialog(const char id) mReviewDialog->setFatigue(mPlayerFatigue); { - std::map > attributes = mWM->getPlayerAttributeValues(); - for (std::map >::iterator it = attributes.begin(); + std::map > attributes = mWM->getPlayerAttributeValues(); + for (std::map >::iterator it = attributes.begin(); it != attributes.end(); ++it) { - mReviewDialog->setAttribute(it->first, it->second); + mReviewDialog->setAttribute(static_cast (it->first), it->second); } } { - std::map > skills = mWM->getPlayerSkillValues(); - for (std::map >::iterator it = skills.begin(); + std::map > skills = mWM->getPlayerSkillValues(); + for (std::map >::iterator it = skills.begin(); it != skills.end(); ++it) { - mReviewDialog->setSkillValue(it->first, it->second); + mReviewDialog->setSkillValue(static_cast (it->first), it->second); } mReviewDialog->configureSkills(mWM->getPlayerMajorSkills(), mWM->getPlayerMinorSkills()); } @@ -302,24 +311,24 @@ void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& v void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) { - if (mReviewDialog) - mWM->removeDialog(mReviewDialog); + mWM->removeDialog(mReviewDialog); + mReviewDialog = 0; mWM->popGuiMode(); } void CharacterCreation::onReviewDialogBack() { - if (mReviewDialog) - mWM->removeDialog(mReviewDialog); + mWM->removeDialog(mReviewDialog); + mReviewDialog = 0; mWM->pushGuiMode(GM_Birth); } void CharacterCreation::onReviewActivateDialog(int parDialog) { - if (mReviewDialog) - mWM->removeDialog(mReviewDialog); + mWM->removeDialog(mReviewDialog); + mReviewDialog = 0; mCreationStage = CSE_ReviewNext; mWM->popGuiMode(); @@ -354,6 +363,7 @@ void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) mWM->setPlayerClass(mPlayerClass); } mWM->removeDialog(mPickClassDialog); + mPickClassDialog = 0; } //TODO This bit gets repeated a few times; wrap it in a function @@ -382,6 +392,7 @@ void CharacterCreation::onPickClassDialogBack() if (!classId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); mWM->removeDialog(mPickClassDialog); + mPickClassDialog = 0; } mWM->popGuiMode(); @@ -390,10 +401,8 @@ void CharacterCreation::onPickClassDialogBack() void CharacterCreation::onClassChoice(int _index) { - if (mClassChoiceDialog) - { - mWM->removeDialog(mClassChoiceDialog); - } + mWM->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; mWM->popGuiMode(); @@ -423,6 +432,7 @@ void CharacterCreation::onNameDialogDone(WindowBase* parWindow) mWM->setValue("name", mPlayerName); MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); mWM->removeDialog(mNameDialog); + mNameDialog = 0; } if (mCreationStage == CSE_ReviewNext) @@ -450,6 +460,7 @@ void CharacterCreation::onRaceDialogBack() if (!mPlayerRaceId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); mWM->removeDialog(mRaceDialog); + mRaceDialog = 0; } mWM->popGuiMode(); @@ -465,6 +476,7 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) if (!mPlayerRaceId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); mWM->removeDialog(mRaceDialog); + mRaceDialog = 0; } if (mCreationStage == CSE_ReviewNext) @@ -492,6 +504,7 @@ void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) if (!mPlayerBirthSignId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); mWM->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; } if (mCreationStage >= CSE_BirthSignChosen) @@ -512,6 +525,7 @@ void CharacterCreation::onBirthSignDialogBack() { MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); mWM->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; } mWM->popGuiMode(); @@ -547,6 +561,7 @@ void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) mWM->setPlayerClass(klass); mWM->removeDialog(mCreateClassDialog); + mCreateClassDialog = 0; } if (mCreationStage == CSE_ReviewNext) @@ -568,8 +583,8 @@ void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) void CharacterCreation::onCreateClassDialogBack() { - if (mCreateClassDialog) - mWM->removeDialog(mCreateClassDialog); + mWM->removeDialog(mCreateClassDialog); + mCreateClassDialog = 0; mWM->popGuiMode(); mWM->pushGuiMode(GM_Class); @@ -579,8 +594,9 @@ void CharacterCreation::onClassQuestionChosen(int _index) { MWBase::Environment::get().getSoundManager()->stopSay(); - if (mGenerateClassQuestionDialog) - mWM->removeDialog(mGenerateClassQuestionDialog); + mWM->removeDialog(mGenerateClassQuestionDialog); + mGenerateClassQuestionDialog = 0; + if (_index < 0 || _index >= 3) { mWM->popGuiMode(); @@ -657,8 +673,9 @@ void CharacterCreation::showClassQuestionDialog() } } - if (mGenerateClassResultDialog) - mWM->removeDialog(mGenerateClassResultDialog); + mWM->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + mGenerateClassResultDialog = new GenerateClassResultDialog(*mWM); mGenerateClassResultDialog->setClassId(mGenerateClass); mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); @@ -674,8 +691,9 @@ void CharacterCreation::showClassQuestionDialog() return; } - if (mGenerateClassQuestionDialog) - mWM->removeDialog(mGenerateClassQuestionDialog); + mWM->removeDialog(mGenerateClassQuestionDialog); + mGenerateClassQuestionDialog = 0; + mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM); InfoBoxDialog::ButtonList buttons; @@ -695,8 +713,9 @@ void CharacterCreation::onGenerateClassBack() if(mCreationStage < CSE_ClassChosen) mCreationStage = CSE_ClassChosen; - if (mGenerateClassResultDialog) - mWM->removeDialog(mGenerateClassResultDialog); + mWM->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); mWM->popGuiMode(); @@ -705,8 +724,9 @@ void CharacterCreation::onGenerateClassBack() void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { - if (mGenerateClassResultDialog) - mWM->removeDialog(mGenerateClassResultDialog); + mWM->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); const ESM::Class *klass = MWBase::Environment::get().getWorld()->getStore().classes.find(mGenerateClass); mPlayerClass = *klass; diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 02b48ffe2..d65763d0c 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -1,16 +1,15 @@ #ifndef CHARACTER_CREATION_HPP #define CHARACTER_CREATION_HPP -#include "window_manager.hpp" - -#include "../mwmechanics/mechanicsmanager.hpp" -#include "../mwmechanics/stat.hpp" -#include "../mwworld/world.hpp" #include +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwmechanics/stat.hpp" + namespace MWGui { - class WindowManager; class WindowBase; class TextInputDialog; @@ -30,7 +29,7 @@ namespace MWGui public: typedef std::vector SkillList; - CharacterCreation(WindowManager* _wm); + CharacterCreation(MWBase::WindowManager* _wm); ~CharacterCreation(); //Show a dialog @@ -59,7 +58,7 @@ namespace MWGui BirthDialog* mBirthSignDialog; ReviewDialog* mReviewDialog; - WindowManager* mWM; + MWBase::WindowManager* mWM; //Player data std::string mPlayerName; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 0961f6327..eaf191819 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -1,6 +1,5 @@ #include "class.hpp" -#include #include #include @@ -8,7 +7,10 @@ #include -#include "window_manager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + #include "tooltips.hpp" #undef min @@ -18,16 +20,16 @@ using namespace MWGui; /* GenerateClassResultDialog */ -GenerateClassResultDialog::GenerateClassResultDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_generate_class_result_layout.xml", parWindowManager) +GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_generate_class_result.layout", parWindowManager) { // Centre dialog center(); setText("ReflectT", mWindowManager.getGameSettingString("sMessageQuestionAnswer1", "")); - getWidget(classImage, "ClassImage"); - getWidget(className, "ClassName"); + getWidget(mClassImage, "ClassImage"); + getWidget(mClassName, "ClassName"); MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); @@ -51,15 +53,14 @@ void GenerateClassResultDialog::open() std::string GenerateClassResultDialog::getClassId() const { - return className->getCaption(); + return mClassName->getCaption(); } void GenerateClassResultDialog::setClassId(const std::string &classId) { - currentClassId = classId; - classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); - const ESMS::ESMStore &store = mWindowManager.getStore(); - className->setCaption(store.classes.find(currentClassId)->name); + mCurrentClassId = classId; + mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); + mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().classes.find(mCurrentClassId)->name); } // widget controls @@ -76,35 +77,35 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) /* PickClassDialog */ -PickClassDialog::PickClassDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_class_layout.xml", parWindowManager) +PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_class.layout", parWindowManager) { // Centre dialog center(); - getWidget(specializationName, "SpecializationName"); + getWidget(mSpecializationName, "SpecializationName"); - getWidget(favoriteAttribute[0], "FavoriteAttribute0"); - getWidget(favoriteAttribute[1], "FavoriteAttribute1"); - favoriteAttribute[0]->setWindowManager(&mWindowManager); - favoriteAttribute[1]->setWindowManager(&mWindowManager); + getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); + getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); + mFavoriteAttribute[0]->setWindowManager(&mWindowManager); + mFavoriteAttribute[1]->setWindowManager(&mWindowManager); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; - getWidget(majorSkill[i], std::string("MajorSkill").append(1, theIndex)); - getWidget(minorSkill[i], std::string("MinorSkill").append(1, theIndex)); - majorSkill[i]->setWindowManager(&mWindowManager); - minorSkill[i]->setWindowManager(&mWindowManager); + getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); + getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); + mMajorSkill[i]->setWindowManager(&mWindowManager); + mMinorSkill[i]->setWindowManager(&mWindowManager); } - getWidget(classList, "ClassList"); - classList->setScrollVisible(true); - classList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - classList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - classList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + getWidget(mClassList, "ClassList"); + mClassList->setScrollVisible(true); + mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - getWidget(classImage, "ClassImage"); + getWidget(mClassImage, "ClassImage"); MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); @@ -148,14 +149,14 @@ void PickClassDialog::open() void PickClassDialog::setClassId(const std::string &classId) { - currentClassId = classId; - classList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = classList->getItemCount(); + mCurrentClassId = classId; + mClassList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mClassList->getItemCount(); for (size_t i = 0; i < count; ++i) { - if (boost::iequals(*classList->getItemDataAt(i), classId)) + if (boost::iequals(*mClassList->getItemDataAt(i), classId)) { - classList->setIndexSelected(i); + mClassList->setIndexSelected(i); break; } } @@ -180,11 +181,11 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - const std::string *classId = classList->getItemDataAt(_index); - if (boost::iequals(currentClassId, *classId)) + const std::string *classId = mClassList->getItemDataAt(_index); + if (boost::iequals(mCurrentClassId, *classId)) return; - currentClassId = *classId; + mCurrentClassId = *classId; updateStats(); } @@ -192,9 +193,9 @@ void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) void PickClassDialog::updateClasses() { - classList->removeAllItems(); + mClassList->removeAllItems(); - const ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); ESMS::RecListT::MapType::const_iterator it = store.classes.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.classes.list.end(); @@ -207,19 +208,19 @@ void PickClassDialog::updateClasses() continue; const std::string &id = it->first; - classList->addItem(klass.name, id); - if (boost::iequals(id, currentClassId)) - classList->setIndexSelected(index); + mClassList->addItem(klass.name, id); + if (boost::iequals(id, mCurrentClassId)) + mClassList->setIndexSelected(index); ++index; } } void PickClassDialog::updateStats() { - if (currentClassId.empty()) + if (mCurrentClassId.empty()) return; - const ESMS::ESMStore &store = mWindowManager.getStore(); - const ESM::Class *klass = store.classes.search(currentClassId); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Class *klass = store.classes.search(mCurrentClassId); if (!klass) return; @@ -231,23 +232,23 @@ void PickClassDialog::updateStats() "sSpecializationStealth" }; std::string specName = mWindowManager.getGameSettingString(specIds[specialization], specIds[specialization]); - specializationName->setCaption(specName); - ToolTips::createSpecializationToolTip(specializationName, specName, specialization); + mSpecializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); - favoriteAttribute[0]->setAttributeId(klass->data.attribute[0]); - favoriteAttribute[1]->setAttributeId(klass->data.attribute[1]); - ToolTips::createAttributeToolTip(favoriteAttribute[0], favoriteAttribute[0]->getAttributeId()); - ToolTips::createAttributeToolTip(favoriteAttribute[1], favoriteAttribute[1]->getAttributeId()); + mFavoriteAttribute[0]->setAttributeId(klass->data.attribute[0]); + mFavoriteAttribute[1]->setAttributeId(klass->data.attribute[1]); + ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); for (int i = 0; i < 5; ++i) { - minorSkill[i]->setSkillNumber(klass->data.skills[i][0]); - majorSkill[i]->setSkillNumber(klass->data.skills[i][1]); - ToolTips::createSkillToolTip(minorSkill[i], klass->data.skills[i][0]); - ToolTips::createSkillToolTip(majorSkill[i], klass->data.skills[i][1]); + mMinorSkill[i]->setSkillNumber(klass->data.skills[i][0]); + mMajorSkill[i]->setSkillNumber(klass->data.skills[i][1]); + ToolTips::createSkillToolTip(mMinorSkill[i], klass->data.skills[i][0]); + ToolTips::createSkillToolTip(mMajorSkill[i], klass->data.skills[i][1]); } - classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds"); + mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); } /* InfoBoxDialog */ @@ -282,61 +283,61 @@ void InfoBoxDialog::layoutVertically(MyGUI::WidgetPtr widget, int margin) widget->setSize(width, pos); } -InfoBoxDialog::InfoBoxDialog(WindowManager& parWindowManager) - : WindowBase("openmw_infobox_layout.xml", parWindowManager) - , currentButton(-1) +InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_infobox.layout", parWindowManager) + , mCurrentButton(-1) { - getWidget(textBox, "TextBox"); - getWidget(text, "Text"); - text->getSubWidgetText()->setWordWrap(true); - getWidget(buttonBar, "ButtonBar"); + getWidget(mTextBox, "TextBox"); + getWidget(mText, "Text"); + mText->getSubWidgetText()->setWordWrap(true); + getWidget(mButtonBar, "ButtonBar"); center(); } void InfoBoxDialog::setText(const std::string &str) { - text->setCaption(str); - textBox->setVisible(!str.empty()); - fitToText(text); + mText->setCaption(str); + mTextBox->setVisible(!str.empty()); + fitToText(mText); } std::string InfoBoxDialog::getText() const { - return text->getCaption(); + return mText->getCaption(); } void InfoBoxDialog::setButtons(ButtonList &buttons) { - for (std::vector::iterator it = this->buttons.begin(); it != this->buttons.end(); ++it) + for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } - this->buttons.clear(); - currentButton = -1; + this->mButtons.clear(); + mCurrentButton = -1; // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget MyGUI::ButtonPtr button; - MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, buttonBar->getWidth(), 10); + MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); ButtonList::const_iterator end = buttons.end(); for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) { const std::string &text = *it; - button = buttonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); + button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); button->getSubWidgetText()->setWordWrap(true); button->setCaption(text); fitToText(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); coord.top += button->getHeight(); - this->buttons.push_back(button); + this->mButtons.push_back(button); } } void InfoBoxDialog::open() { // Fix layout - layoutVertically(textBox, 4); - layoutVertically(buttonBar, 6); + layoutVertically(mTextBox, 4); + layoutVertically(mButtonBar, 6); layoutVertically(mMainWidget, 4 + 6); center(); @@ -345,18 +346,18 @@ void InfoBoxDialog::open() int InfoBoxDialog::getChosenButton() const { - return currentButton; + return mCurrentButton; } void InfoBoxDialog::onButtonClicked(MyGUI::WidgetPtr _sender) { - std::vector::const_iterator end = buttons.end(); + std::vector::const_iterator end = mButtons.end(); int i = 0; - for (std::vector::const_iterator it = buttons.begin(); it != end; ++it) + for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) { if (*it == _sender) { - currentButton = i; + mCurrentButton = i; eventButtonSelected(i); return; } @@ -366,7 +367,7 @@ void InfoBoxDialog::onButtonClicked(MyGUI::WidgetPtr _sender) /* ClassChoiceDialog */ -ClassChoiceDialog::ClassChoiceDialog(WindowManager& parWindowManager) +ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) : InfoBoxDialog(parWindowManager) { setText(""); @@ -380,51 +381,51 @@ ClassChoiceDialog::ClassChoiceDialog(WindowManager& parWindowManager) /* CreateClassDialog */ -CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_create_class_layout.xml", parWindowManager) - , specDialog(nullptr) - , attribDialog(nullptr) - , skillDialog(nullptr) - , descDialog(nullptr) +CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_create_class.layout", parWindowManager) + , mSpecDialog(nullptr) + , mAttribDialog(nullptr) + , mSkillDialog(nullptr) + , mDescDialog(nullptr) { // Centre dialog center(); setText("SpecializationT", mWindowManager.getGameSettingString("sChooseClassMenu1", "Specialization")); - getWidget(specializationName, "SpecializationName"); - specializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); + getWidget(mSpecializationName, "SpecializationName"); + mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); setText("FavoriteAttributesT", mWindowManager.getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); - getWidget(favoriteAttribute0, "FavoriteAttribute0"); - getWidget(favoriteAttribute1, "FavoriteAttribute1"); - favoriteAttribute0->setWindowManager(&mWindowManager); - favoriteAttribute1->setWindowManager(&mWindowManager); - favoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - favoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); + getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); + mFavoriteAttribute0->setWindowManager(&mWindowManager); + mFavoriteAttribute1->setWindowManager(&mWindowManager); + mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); setText("MajorSkillT", mWindowManager.getGameSettingString("sSkillClassMajor", "")); setText("MinorSkillT", mWindowManager.getGameSettingString("sSkillClassMinor", "")); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; - getWidget(majorSkill[i], std::string("MajorSkill").append(1, theIndex)); - getWidget(minorSkill[i], std::string("MinorSkill").append(1, theIndex)); - skills.push_back(majorSkill[i]); - skills.push_back(minorSkill[i]); + getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); + getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); + mSkills.push_back(mMajorSkill[i]); + mSkills.push_back(mMinorSkill[i]); } - std::vector::const_iterator end = skills.end(); - for (std::vector::const_iterator it = skills.begin(); it != end; ++it) + std::vector::const_iterator end = mSkills.end(); + for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) { (*it)->setWindowManager(&mWindowManager); (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); } setText("LabelT", mWindowManager.getGameSettingString("sName", "")); - getWidget(editName, "EditName"); + getWidget(mEditName, "EditName"); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(editName); + MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); MyGUI::ButtonPtr descriptionButton; getWidget(descriptionButton, "DescriptionButton"); @@ -441,20 +442,20 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) // Set default skills, attributes - favoriteAttribute0->setAttributeId(ESM::Attribute::Strength); - favoriteAttribute1->setAttributeId(ESM::Attribute::Agility); + mFavoriteAttribute0->setAttributeId(ESM::Attribute::Strength); + mFavoriteAttribute1->setAttributeId(ESM::Attribute::Agility); - majorSkill[0]->setSkillId(ESM::Skill::Block); - majorSkill[1]->setSkillId(ESM::Skill::Armorer); - majorSkill[2]->setSkillId(ESM::Skill::MediumArmor); - majorSkill[3]->setSkillId(ESM::Skill::HeavyArmor); - majorSkill[4]->setSkillId(ESM::Skill::BluntWeapon); + mMajorSkill[0]->setSkillId(ESM::Skill::Block); + mMajorSkill[1]->setSkillId(ESM::Skill::Armorer); + mMajorSkill[2]->setSkillId(ESM::Skill::MediumArmor); + mMajorSkill[3]->setSkillId(ESM::Skill::HeavyArmor); + mMajorSkill[4]->setSkillId(ESM::Skill::BluntWeapon); - minorSkill[0]->setSkillId(ESM::Skill::LongBlade); - minorSkill[1]->setSkillId(ESM::Skill::Axe); - minorSkill[2]->setSkillId(ESM::Skill::Spear); - minorSkill[3]->setSkillId(ESM::Skill::Athletics); - minorSkill[4]->setSkillId(ESM::Skill::Enchant); + mMinorSkill[0]->setSkillId(ESM::Skill::LongBlade); + mMinorSkill[1]->setSkillId(ESM::Skill::Axe); + mMinorSkill[2]->setSkillId(ESM::Skill::Spear); + mMinorSkill[3]->setSkillId(ESM::Skill::Athletics); + mMinorSkill[4]->setSkillId(ESM::Skill::Enchant); setSpecialization(0); update(); @@ -462,44 +463,44 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) CreateClassDialog::~CreateClassDialog() { - delete specDialog; - delete attribDialog; - delete skillDialog; - delete descDialog; + delete mSpecDialog; + delete mAttribDialog; + delete mSkillDialog; + delete mDescDialog; } void CreateClassDialog::update() { for (int i = 0; i < 5; ++i) { - ToolTips::createSkillToolTip(majorSkill[i], majorSkill[i]->getSkillId()); - ToolTips::createSkillToolTip(minorSkill[i], minorSkill[i]->getSkillId()); + ToolTips::createSkillToolTip(mMajorSkill[i], mMajorSkill[i]->getSkillId()); + ToolTips::createSkillToolTip(mMinorSkill[i], mMinorSkill[i]->getSkillId()); } - ToolTips::createAttributeToolTip(favoriteAttribute0, favoriteAttribute0->getAttributeId()); - ToolTips::createAttributeToolTip(favoriteAttribute1, favoriteAttribute1->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute0, mFavoriteAttribute0->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute1, mFavoriteAttribute1->getAttributeId()); } std::string CreateClassDialog::getName() const { - return editName->getOnlyText(); + return mEditName->getOnlyText(); } std::string CreateClassDialog::getDescription() const { - return description; + return mDescription; } ESM::Class::Specialization CreateClassDialog::getSpecializationId() const { - return specializationId; + return mSpecializationId; } std::vector CreateClassDialog::getFavoriteAttributes() const { std::vector v; - v.push_back(favoriteAttribute0->getAttributeId()); - v.push_back(favoriteAttribute1->getAttributeId()); + v.push_back(mFavoriteAttribute0->getAttributeId()); + v.push_back(mFavoriteAttribute1->getAttributeId()); return v; } @@ -508,7 +509,7 @@ std::vector CreateClassDialog::getMajorSkills() const std::vector v; for(int i = 0; i < 5; i++) { - v.push_back(majorSkill[i]->getSkillId()); + v.push_back(mMajorSkill[i]->getSkillId()); } return v; } @@ -518,7 +519,7 @@ std::vector CreateClassDialog::getMinorSkills() const std::vector v; for(int i=0; i < 5; i++) { - v.push_back(minorSkill[i]->getSkillId()); + v.push_back(mMinorSkill[i]->getSkillId()); } return v; } @@ -557,108 +558,99 @@ void CreateClassDialog::open() void CreateClassDialog::onDialogCancel() { - if (specDialog) - { - mWindowManager.removeDialog(specDialog); - specDialog = 0; - } - if (attribDialog) - { - mWindowManager.removeDialog(attribDialog); - attribDialog = 0; - } - if (skillDialog) - { - mWindowManager.removeDialog(skillDialog); - skillDialog = 0; - } - if (descDialog) - { - mWindowManager.removeDialog(descDialog); - descDialog = 0; - } + mWindowManager.removeDialog(mSpecDialog); + mSpecDialog = 0; + + mWindowManager.removeDialog(mAttribDialog); + mAttribDialog = 0; + + mWindowManager.removeDialog(mSkillDialog); + mSkillDialog = 0; + + mWindowManager.removeDialog(mDescDialog); + mDescDialog = 0; } void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) { - delete specDialog; - specDialog = new SelectSpecializationDialog(mWindowManager); - specDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - specDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); - specDialog->setVisible(true); + delete mSpecDialog; + mSpecDialog = new SelectSpecializationDialog(mWindowManager); + mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); + mSpecDialog->setVisible(true); } void CreateClassDialog::onSpecializationSelected() { - specializationId = specDialog->getSpecializationId(); - setSpecialization(specializationId); + mSpecializationId = mSpecDialog->getSpecializationId(); + setSpecialization(mSpecializationId); - mWindowManager.removeDialog(specDialog); - specDialog = 0; + mWindowManager.removeDialog(mSpecDialog); + mSpecDialog = 0; } void CreateClassDialog::setSpecialization(int id) { - specializationId = (ESM::Class::Specialization) id; + mSpecializationId = (ESM::Class::Specialization) id; static const char *specIds[3] = { "sSpecializationCombat", "sSpecializationMagic", "sSpecializationStealth" }; - std::string specName = mWindowManager.getGameSettingString(specIds[specializationId], specIds[specializationId]); - specializationName->setCaption(specName); - ToolTips::createSpecializationToolTip(specializationName, specName, specializationId); + std::string specName = mWindowManager.getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); + mSpecializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); } void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { - delete attribDialog; - attribDialog = new SelectAttributeDialog(mWindowManager); - attribDialog->setAffectedWidget(_sender); - attribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - attribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); - attribDialog->setVisible(true); + delete mAttribDialog; + mAttribDialog = new SelectAttributeDialog(mWindowManager); + mAttribDialog->setAffectedWidget(_sender); + mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); + mAttribDialog->setVisible(true); } void CreateClassDialog::onAttributeSelected() { - ESM::Attribute::AttributeID id = attribDialog->getAttributeId(); - Widgets::MWAttributePtr attribute = attribDialog->getAffectedWidget(); - if (attribute == favoriteAttribute0) + ESM::Attribute::AttributeID id = mAttribDialog->getAttributeId(); + Widgets::MWAttributePtr attribute = mAttribDialog->getAffectedWidget(); + if (attribute == mFavoriteAttribute0) { - if (favoriteAttribute1->getAttributeId() == id) - favoriteAttribute1->setAttributeId(favoriteAttribute0->getAttributeId()); + if (mFavoriteAttribute1->getAttributeId() == id) + mFavoriteAttribute1->setAttributeId(mFavoriteAttribute0->getAttributeId()); } - else if (attribute == favoriteAttribute1) + else if (attribute == mFavoriteAttribute1) { - if (favoriteAttribute0->getAttributeId() == id) - favoriteAttribute0->setAttributeId(favoriteAttribute1->getAttributeId()); + if (mFavoriteAttribute0->getAttributeId() == id) + mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); } attribute->setAttributeId(id); - mWindowManager.removeDialog(attribDialog); - attribDialog = 0; + mWindowManager.removeDialog(mAttribDialog); + mAttribDialog = 0; update(); } void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { - delete skillDialog; - skillDialog = new SelectSkillDialog(mWindowManager); - skillDialog->setAffectedWidget(_sender); - skillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - skillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); - skillDialog->setVisible(true); + delete mSkillDialog; + mSkillDialog = new SelectSkillDialog(mWindowManager); + mSkillDialog->setAffectedWidget(_sender); + mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); + mSkillDialog->setVisible(true); } void CreateClassDialog::onSkillSelected() { - ESM::Skill::SkillEnum id = skillDialog->getSkillId(); - Widgets::MWSkillPtr skill = skillDialog->getAffectedWidget(); + ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); + Widgets::MWSkillPtr skill = mSkillDialog->getAffectedWidget(); // Avoid duplicate skills by swapping any skill field that matches the selected one - std::vector::const_iterator end = skills.end(); - for (std::vector::const_iterator it = skills.begin(); it != end; ++it) + std::vector::const_iterator end = mSkills.end(); + for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) { if (*it == skill) continue; @@ -669,25 +661,25 @@ void CreateClassDialog::onSkillSelected() } } - skill->setSkillId(skillDialog->getSkillId()); - mWindowManager.removeDialog(skillDialog); - skillDialog = 0; + skill->setSkillId(mSkillDialog->getSkillId()); + mWindowManager.removeDialog(mSkillDialog); + mSkillDialog = 0; update(); } void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) { - descDialog = new DescriptionDialog(mWindowManager); - descDialog->setTextInput(description); - descDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); - descDialog->setVisible(true); + mDescDialog = new DescriptionDialog(mWindowManager); + mDescDialog->setTextInput(mDescription); + mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); + mDescDialog->setVisible(true); } void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) { - description = descDialog->getTextInput(); - mWindowManager.removeDialog(descDialog); - descDialog = 0; + mDescription = mDescDialog->getTextInput(); + mWindowManager.removeDialog(mDescDialog); + mDescDialog = 0; } void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) @@ -702,32 +694,32 @@ void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) /* SelectSpecializationDialog */ -SelectSpecializationDialog::SelectSpecializationDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_select_specialization_layout.xml", parWindowManager) +SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_select_specialization.layout", parWindowManager) { // Centre dialog center(); setText("LabelT", mWindowManager.getGameSettingString("sSpecializationMenu1", "")); - getWidget(specialization0, "Specialization0"); - getWidget(specialization1, "Specialization1"); - getWidget(specialization2, "Specialization2"); + getWidget(mSpecialization0, "Specialization0"); + getWidget(mSpecialization1, "Specialization1"); + getWidget(mSpecialization2, "Specialization2"); std::string combat = mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], ""); std::string magic = mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Magic], ""); std::string stealth = mWindowManager.getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Stealth], ""); - specialization0->setCaption(combat); - specialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - specialization1->setCaption(magic); - specialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - specialization2->setCaption(stealth); - specialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - specializationId = ESM::Class::Combat; + mSpecialization0->setCaption(combat); + mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecialization1->setCaption(magic); + mSpecialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecialization2->setCaption(stealth); + mSpecialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecializationId = ESM::Class::Combat; - ToolTips::createSpecializationToolTip(specialization0, combat, ESM::Class::Combat); - ToolTips::createSpecializationToolTip(specialization1, magic, ESM::Class::Magic); - ToolTips::createSpecializationToolTip(specialization2, stealth, ESM::Class::Stealth); + ToolTips::createSpecializationToolTip(mSpecialization0, combat, ESM::Class::Combat); + ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); + ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); MyGUI::ButtonPtr cancelButton; getWidget(cancelButton, "CancelButton"); @@ -748,12 +740,12 @@ SelectSpecializationDialog::~SelectSpecializationDialog() void SelectSpecializationDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender) { - if (_sender == specialization0) - specializationId = ESM::Class::Combat; - else if (_sender == specialization1) - specializationId = ESM::Class::Magic; - else if (_sender == specialization2) - specializationId = ESM::Class::Stealth; + if (_sender == mSpecialization0) + mSpecializationId = ESM::Class::Combat; + else if (_sender == mSpecialization1) + mSpecializationId = ESM::Class::Magic; + else if (_sender == mSpecialization2) + mSpecializationId = ESM::Class::Stealth; else return; @@ -767,8 +759,8 @@ void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) /* SelectAttributeDialog */ -SelectAttributeDialog::SelectAttributeDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_select_attribute_layout.xml", parWindowManager) +SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_select_attribute.layout", parWindowManager) { // Centre dialog center(); @@ -807,7 +799,7 @@ SelectAttributeDialog::~SelectAttributeDialog() void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { // TODO: Change MWAttribute to set and get AttributeID enum instead of int - attributeId = static_cast(_sender->getAttributeId()); + mAttributeId = static_cast(_sender->getAttributeId()); eventItemSelected(); } @@ -819,8 +811,8 @@ void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) /* SelectSkillDialog */ -SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_select_skill_layout.xml", parWindowManager) +SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_select_skill.layout", parWindowManager) { // Centre dialog center(); @@ -833,44 +825,44 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) for(int i = 0; i < 9; i++) { char theIndex = '0'+i; - getWidget(combatSkill[i], std::string("CombatSkill").append(1, theIndex)); - getWidget(magicSkill[i], std::string("MagicSkill").append(1, theIndex)); - getWidget(stealthSkill[i], std::string("StealthSkill").append(1, theIndex)); + getWidget(mCombatSkill[i], std::string("CombatSkill").append(1, theIndex)); + getWidget(mMagicSkill[i], std::string("MagicSkill").append(1, theIndex)); + getWidget(mStealthSkill[i], std::string("StealthSkill").append(1, theIndex)); } - struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} skills[3][9] = { + struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} mSkills[3][9] = { { - {combatSkill[0], ESM::Skill::Block}, - {combatSkill[1], ESM::Skill::Armorer}, - {combatSkill[2], ESM::Skill::MediumArmor}, - {combatSkill[3], ESM::Skill::HeavyArmor}, - {combatSkill[4], ESM::Skill::BluntWeapon}, - {combatSkill[5], ESM::Skill::LongBlade}, - {combatSkill[6], ESM::Skill::Axe}, - {combatSkill[7], ESM::Skill::Spear}, - {combatSkill[8], ESM::Skill::Athletics} + {mCombatSkill[0], ESM::Skill::Block}, + {mCombatSkill[1], ESM::Skill::Armorer}, + {mCombatSkill[2], ESM::Skill::MediumArmor}, + {mCombatSkill[3], ESM::Skill::HeavyArmor}, + {mCombatSkill[4], ESM::Skill::BluntWeapon}, + {mCombatSkill[5], ESM::Skill::LongBlade}, + {mCombatSkill[6], ESM::Skill::Axe}, + {mCombatSkill[7], ESM::Skill::Spear}, + {mCombatSkill[8], ESM::Skill::Athletics} }, { - {magicSkill[0], ESM::Skill::Enchant}, - {magicSkill[1], ESM::Skill::Destruction}, - {magicSkill[2], ESM::Skill::Alteration}, - {magicSkill[3], ESM::Skill::Illusion}, - {magicSkill[4], ESM::Skill::Conjuration}, - {magicSkill[5], ESM::Skill::Mysticism}, - {magicSkill[6], ESM::Skill::Restoration}, - {magicSkill[7], ESM::Skill::Alchemy}, - {magicSkill[8], ESM::Skill::Unarmored} + {mMagicSkill[0], ESM::Skill::Enchant}, + {mMagicSkill[1], ESM::Skill::Destruction}, + {mMagicSkill[2], ESM::Skill::Alteration}, + {mMagicSkill[3], ESM::Skill::Illusion}, + {mMagicSkill[4], ESM::Skill::Conjuration}, + {mMagicSkill[5], ESM::Skill::Mysticism}, + {mMagicSkill[6], ESM::Skill::Restoration}, + {mMagicSkill[7], ESM::Skill::Alchemy}, + {mMagicSkill[8], ESM::Skill::Unarmored} }, { - {stealthSkill[0], ESM::Skill::Security}, - {stealthSkill[1], ESM::Skill::Sneak}, - {stealthSkill[2], ESM::Skill::Acrobatics}, - {stealthSkill[3], ESM::Skill::LightArmor}, - {stealthSkill[4], ESM::Skill::ShortBlade}, - {stealthSkill[5] ,ESM::Skill::Marksman}, - {stealthSkill[6] ,ESM::Skill::Mercantile}, - {stealthSkill[7] ,ESM::Skill::Speechcraft}, - {stealthSkill[8] ,ESM::Skill::HandToHand} + {mStealthSkill[0], ESM::Skill::Security}, + {mStealthSkill[1], ESM::Skill::Sneak}, + {mStealthSkill[2], ESM::Skill::Acrobatics}, + {mStealthSkill[3], ESM::Skill::LightArmor}, + {mStealthSkill[4], ESM::Skill::ShortBlade}, + {mStealthSkill[5] ,ESM::Skill::Marksman}, + {mStealthSkill[6] ,ESM::Skill::Mercantile}, + {mStealthSkill[7] ,ESM::Skill::Speechcraft}, + {mStealthSkill[8] ,ESM::Skill::HandToHand} } }; @@ -878,10 +870,10 @@ SelectSkillDialog::SelectSkillDialog(WindowManager& parWindowManager) { for (int i = 0; i < 9; ++i) { - skills[spec][i].widget->setWindowManager(&mWindowManager); - skills[spec][i].widget->setSkillId(skills[spec][i].skillId); - skills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); - ToolTips::createSkillToolTip(skills[spec][i].widget, skills[spec][i].widget->getSkillId()); + mSkills[spec][i].widget->setWindowManager(&mWindowManager); + mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); + mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); + ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); } } @@ -904,7 +896,7 @@ SelectSkillDialog::~SelectSkillDialog() void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { - skillId = _sender->getSkillId(); + mSkillId = _sender->getSkillId(); eventItemSelected(); } @@ -915,13 +907,13 @@ void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) /* DescriptionDialog */ -DescriptionDialog::DescriptionDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_class_description_layout.xml", parWindowManager) +DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_class_description.layout", parWindowManager) { // Centre dialog center(); - getWidget(textEdit, "TextEdit"); + getWidget(mTextEdit, "TextEdit"); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); @@ -931,7 +923,7 @@ DescriptionDialog::DescriptionDialog(WindowManager& parWindowManager) okButton->setCoord(234 - buttonWidth, 214, buttonWidth, 24); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit); + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); MyGUI::InputManager::getInstance().addWidgetModal(mMainWidget); } diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 868052800..4baceed1e 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -7,19 +7,18 @@ /* This file contains the dialogs for choosing a class. - Layout is defined by resources/mygui/openmw_chargen_class_layout.xml. + Layout is defined by resources/mygui/openmw_chargen_class.layout. */ namespace MWGui { + /// \todo remove! using namespace MyGUI; - class WindowManager; - class InfoBoxDialog : public WindowBase { public: - InfoBoxDialog(WindowManager& parWindowManager); + InfoBoxDialog(MWBase::WindowManager& parWindowManager); typedef std::vector ButtonList; @@ -45,11 +44,11 @@ namespace MWGui void fitToText(MyGUI::TextBox* widget); void layoutVertically(MyGUI::WidgetPtr widget, int margin); - int currentButton; - MyGUI::WidgetPtr textBox; - MyGUI::TextBox* text; - MyGUI::WidgetPtr buttonBar; - std::vector buttons; + int mCurrentButton; + MyGUI::WidgetPtr mTextBox; + MyGUI::TextBox* mText; + MyGUI::WidgetPtr mButtonBar; + std::vector mButtons; }; // Lets the player choose between 3 ways of creating a class @@ -64,13 +63,13 @@ namespace MWGui Class_Create = 2, Class_Back = 3 }; - ClassChoiceDialog(WindowManager& parWindowManager); + ClassChoiceDialog(MWBase::WindowManager& parWindowManager); }; class GenerateClassResultDialog : public WindowBase { public: - GenerateClassResultDialog(WindowManager& parWindowManager); + GenerateClassResultDialog(MWBase::WindowManager& parWindowManager); std::string getClassId() const; void setClassId(const std::string &classId); @@ -90,18 +89,18 @@ namespace MWGui void onBackClicked(MyGUI::Widget* _sender); private: - MyGUI::ImageBox* classImage; - MyGUI::TextBox* className; + MyGUI::ImageBox* mClassImage; + MyGUI::TextBox* mClassName; - std::string currentClassId; + std::string mCurrentClassId; }; class PickClassDialog : public WindowBase { public: - PickClassDialog(WindowManager& parWindowManager); + PickClassDialog(MWBase::WindowManager& parWindowManager); - const std::string &getClassId() const { return currentClassId; } + const std::string &getClassId() const { return mCurrentClassId; } void setClassId(const std::string &classId); void setNextButtonShow(bool shown); @@ -125,23 +124,23 @@ namespace MWGui void updateClasses(); void updateStats(); - MyGUI::ImageBox* classImage; - MyGUI::ListBox* classList; - MyGUI::TextBox* specializationName; - Widgets::MWAttributePtr favoriteAttribute[2]; - Widgets::MWSkillPtr majorSkill[5]; - Widgets::MWSkillPtr minorSkill[5]; + MyGUI::ImageBox* mClassImage; + MyGUI::ListBox* mClassList; + MyGUI::TextBox* mSpecializationName; + Widgets::MWAttributePtr mFavoriteAttribute[2]; + Widgets::MWSkillPtr mMajorSkill[5]; + Widgets::MWSkillPtr mMinorSkill[5]; - std::string currentClassId; + std::string mCurrentClassId; }; class SelectSpecializationDialog : public WindowBase { public: - SelectSpecializationDialog(WindowManager& parWindowManager); + SelectSpecializationDialog(MWBase::WindowManager& parWindowManager); ~SelectSpecializationDialog(); - ESM::Class::Specialization getSpecializationId() const { return specializationId; } + ESM::Class::Specialization getSpecializationId() const { return mSpecializationId; } // Events typedef delegates::CMultiDelegate0 EventHandle_Void; @@ -161,20 +160,20 @@ namespace MWGui void onCancelClicked(MyGUI::Widget* _sender); private: - MyGUI::TextBox *specialization0, *specialization1, *specialization2; + MyGUI::TextBox *mSpecialization0, *mSpecialization1, *mSpecialization2; - ESM::Class::Specialization specializationId; + ESM::Class::Specialization mSpecializationId; }; class SelectAttributeDialog : public WindowBase { public: - SelectAttributeDialog(WindowManager& parWindowManager); + SelectAttributeDialog(MWBase::WindowManager& parWindowManager); ~SelectAttributeDialog(); - ESM::Attribute::AttributeID getAttributeId() const { return attributeId; } - Widgets::MWAttributePtr getAffectedWidget() const { return affectedWidget; } - void setAffectedWidget(Widgets::MWAttributePtr widget) { affectedWidget = widget; } + ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; } + Widgets::MWAttributePtr getAffectedWidget() const { return mAffectedWidget; } + void setAffectedWidget(Widgets::MWAttributePtr widget) { mAffectedWidget = widget; } // Events typedef delegates::CMultiDelegate0 EventHandle_Void; @@ -194,20 +193,20 @@ namespace MWGui void onCancelClicked(MyGUI::Widget* _sender); private: - Widgets::MWAttributePtr affectedWidget; + Widgets::MWAttributePtr mAffectedWidget; - ESM::Attribute::AttributeID attributeId; + ESM::Attribute::AttributeID mAttributeId; }; class SelectSkillDialog : public WindowBase { public: - SelectSkillDialog(WindowManager& parWindowManager); + SelectSkillDialog(MWBase::WindowManager& parWindowManager); ~SelectSkillDialog(); - ESM::Skill::SkillEnum getSkillId() const { return skillId; } - Widgets::MWSkillPtr getAffectedWidget() const { return affectedWidget; } - void setAffectedWidget(Widgets::MWSkillPtr widget) { affectedWidget = widget; } + ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } + Widgets::MWSkillPtr getAffectedWidget() const { return mAffectedWidget; } + void setAffectedWidget(Widgets::MWSkillPtr widget) { mAffectedWidget = widget; } // Events typedef delegates::CMultiDelegate0 EventHandle_Void; @@ -227,34 +226,34 @@ namespace MWGui void onCancelClicked(MyGUI::Widget* _sender); private: - Widgets::MWSkillPtr combatSkill[9]; - Widgets::MWSkillPtr magicSkill[9]; - Widgets::MWSkillPtr stealthSkill[9]; - Widgets::MWSkillPtr affectedWidget; + Widgets::MWSkillPtr mCombatSkill[9]; + Widgets::MWSkillPtr mMagicSkill[9]; + Widgets::MWSkillPtr mStealthSkill[9]; + Widgets::MWSkillPtr mAffectedWidget; - ESM::Skill::SkillEnum skillId; + ESM::Skill::SkillEnum mSkillId; }; class DescriptionDialog : public WindowBase { public: - DescriptionDialog(WindowManager& parWindowManager); + DescriptionDialog(MWBase::WindowManager& parWindowManager); ~DescriptionDialog(); - std::string getTextInput() const { return textEdit ? textEdit->getOnlyText() : ""; } - void setTextInput(const std::string &text) { if (textEdit) textEdit->setOnlyText(text); } + std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } + void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } protected: void onOkClicked(MyGUI::Widget* _sender); private: - MyGUI::EditPtr textEdit; + MyGUI::EditPtr mTextEdit; }; class CreateClassDialog : public WindowBase { public: - CreateClassDialog(WindowManager& parWindowManager); + CreateClassDialog(MWBase::WindowManager& parWindowManager); virtual ~CreateClassDialog(); std::string getName() const; @@ -294,20 +293,20 @@ namespace MWGui void update(); private: - MyGUI::EditPtr editName; - MyGUI::TextBox* specializationName; - Widgets::MWAttributePtr favoriteAttribute0, favoriteAttribute1; - Widgets::MWSkillPtr majorSkill[5]; - Widgets::MWSkillPtr minorSkill[5]; - std::vector skills; - std::string description; + MyGUI::EditPtr mEditName; + MyGUI::TextBox* mSpecializationName; + Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1; + Widgets::MWSkillPtr mMajorSkill[5]; + Widgets::MWSkillPtr mMinorSkill[5]; + std::vector mSkills; + std::string mDescription; - SelectSpecializationDialog *specDialog; - SelectAttributeDialog *attribDialog; - SelectSkillDialog *skillDialog; - DescriptionDialog *descDialog; + SelectSpecializationDialog *mSpecDialog; + SelectAttributeDialog *mAttribDialog; + SelectSkillDialog *mSkillDialog; + DescriptionDialog *mDescDialog; - ESM::Class::Specialization specializationId; + ESM::Class::Specialization mSpecializationId; }; } #endif diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 5e12c3296..1c68da9e5 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -3,12 +3,12 @@ #include #include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" namespace MWGui { - ConfirmationDialog::ConfirmationDialog(WindowManager& parWindowManager) : - WindowBase("openmw_confirmation_dialog_layout.xml", parWindowManager) + ConfirmationDialog::ConfirmationDialog(MWBase::WindowManager& parWindowManager) : + WindowBase("openmw_confirmation_dialog.layout", parWindowManager) { getWidget(mMessage, "Message"); getWidget(mOkButton, "OkButton"); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index d278274a0..a78028b1c 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -8,7 +8,7 @@ namespace MWGui class ConfirmationDialog : public WindowBase { public: - ConfirmationDialog(WindowManager& parWindowManager); + ConfirmationDialog(MWBase::WindowManager& parWindowManager); void open(const std::string& message); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 8115835f4..86c8940a1 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -2,6 +2,10 @@ #include "console.hpp" #include +#include + +#include +#include #include @@ -102,9 +106,10 @@ namespace MWGui } } - Console::Console(int w, int h, const Compiler::Extensions& extensions) - : Layout("openmw_console_layout.xml"), - mCompilerContext (MWScript::CompilerContext::Type_Console) + Console::Console(int w, int h, bool consoleOnlyScripts) + : Layout("openmw_console.layout"), + mCompilerContext (MWScript::CompilerContext::Type_Console), + mConsoleOnlyScripts (consoleOnlyScripts) { setCoord(10,10, w-10, h/2); @@ -123,7 +128,8 @@ namespace MWGui history->setVisibleVScroll(true); // compiler - mCompilerContext.setExtensions (&extensions); + MWScript::registerExtensions (mExtensions, mConsoleOnlyScripts); + mCompilerContext.setExtensions (&mExtensions); } void Console::enable() @@ -170,6 +176,47 @@ namespace MWGui print("#FF2222" + msg + "\n"); } + void Console::execute (const std::string& command) + { + // Log the command + print("#FFFFFF> " + command + "\n"); + + Compiler::Locals locals; + Compiler::Output output (locals); + + if (compile (command + "\n", output)) + { + try + { + ConsoleInterpreterContext interpreterContext (*this, mPtr); + Interpreter::Interpreter interpreter; + MWScript::installOpcodes (interpreter, mConsoleOnlyScripts); + std::vector code; + output.getCode (code); + interpreter.run (&code[0], code.size(), interpreterContext); + } + catch (const std::exception& error) + { + printError (std::string ("An exception has been thrown: ") + error.what()); + } + } + } + + void Console::executeFile (const std::string& path) + { + std::ifstream stream (path.c_str()); + + if (!stream.is_open()) + printError ("failed to open file: " + path); + else + { + std::string line; + + while (std::getline (stream, line)) + execute (line); + } + } + void Console::keyPress(MyGUI::WidgetPtr _sender, MyGUI::KeyCode key, MyGUI::Char _char) @@ -231,28 +278,7 @@ namespace MWGui current = command_history.end(); editString.clear(); - // Log the command - print("#FFFFFF> " + cm + "\n"); - - Compiler::Locals locals; - Compiler::Output output (locals); - - if (compile (cm + "\n", output)) - { - try - { - ConsoleInterpreterContext interpreterContext (*this, mPtr); - Interpreter::Interpreter interpreter; - MWScript::installOpcodes (interpreter); - std::vector code; - output.getCode (code); - interpreter.run (&code[0], code.size(), interpreterContext); - } - catch (const std::exception& error) - { - printError (std::string ("An exception has been thrown: ") + error.what()); - } - } + execute (cm); command->setCaption(""); } diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index eadf4aa4e..1893b0148 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "../mwscript/compilercontext.hpp" @@ -24,8 +25,10 @@ namespace MWGui { private: + Compiler::Extensions mExtensions; MWScript::CompilerContext mCompilerContext; std::vector mNames; + bool mConsoleOnlyScripts; bool compile (const std::string& cmd, Compiler::Output& output); @@ -62,7 +65,7 @@ namespace MWGui StringList::iterator current; std::string editString; - Console(int w, int h, const Compiler::Extensions& extensions); + Console(int w, int h, bool consoleOnlyScripts); void enable(); @@ -86,6 +89,10 @@ namespace MWGui /// Error message void printError(const std::string &msg); + void execute (const std::string& command); + + void executeFile (const std::string& command); + private: void keyPress(MyGUI::WidgetPtr _sender, diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 36ed16b0e..75e2bb3b8 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -3,22 +3,23 @@ #include #include #include -#include +#include #include #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/manualref.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwclass/container.hpp" -#include "../mwinput/inputmanager.hpp" -#include "../mwsound/soundmanager.hpp" -#include "window_manager.hpp" +#include "../mwclass/container.hpp" + #include "widgets.hpp" #include "countdialog.hpp" #include "tradewindow.hpp" @@ -273,7 +274,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside if (mPtr.getTypeName() == typeid(ESM::Container).name()) { - ESMS::LiveCellRef* ref = mPtr.get(); + MWWorld::LiveCellRef* ref = mPtr.get(); if (ref->base->flags & ESM::Container::Organic) { // user notification @@ -556,7 +557,7 @@ void ContainerBase::addItem(MWWorld::Ptr item, int count) { MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - int origCount = item.getRefData().getCount(); + int origCount = item.getRefData().getCount(); item.getRefData().setCount(count); MWWorld::ContainerStoreIterator it = containerStore.add(item); @@ -590,9 +591,9 @@ MWWorld::ContainerStore& ContainerBase::getContainerStore() // ------------------------------------------------------------------------------------------------ -ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) +ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) - , WindowBase("openmw_container_window_layout.xml", parWindowManager) + , WindowBase("openmw_container_window.layout", parWindowManager) { getWidget(mTakeButton, "TakeButton"); getWidget(mCloseButton, "CloseButton"); @@ -612,12 +613,9 @@ ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dr mCloseButton->setCoord(600-20-closeButtonWidth, mCloseButton->getCoord().top, closeButtonWidth, mCloseButton->getCoord().height); mTakeButton->setCoord(600-20-closeButtonWidth-takeButtonWidth-8, mTakeButton->getCoord().top, takeButtonWidth, mTakeButton->getCoord().height); - int w = MyGUI::RenderManager::getInstance().getViewSize().width; - //int h = MyGUI::RenderManager::getInstance().getViewSize().height; - static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); - setCoord(w-600,0,600,300); + setCoord(200,0,600,300); } ContainerWindow::~ContainerWindow() diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 88e445a7b..27c3288ae 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -127,7 +127,7 @@ namespace MWGui class ContainerWindow : public ContainerBase, public WindowBase { public: - ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + ContainerWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop); virtual ~ContainerWindow(); diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index e0a9bb908..6d9415354 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -3,12 +3,12 @@ #include #include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" namespace MWGui { - CountDialog::CountDialog(WindowManager& parWindowManager) : - WindowBase("openmw_count_window_layout.xml", parWindowManager) + CountDialog::CountDialog(MWBase::WindowManager& parWindowManager) : + WindowBase("openmw_count_window.layout", parWindowManager) { getWidget(mSlider, "CountSlider"); getWidget(mItemEdit, "ItemEdit"); @@ -77,7 +77,7 @@ namespace MWGui { if (_sender->getCaption() == "") return; - + unsigned int count; try { diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index aac17b846..6002dadfe 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -8,7 +8,7 @@ namespace MWGui class CountDialog : public WindowBase { public: - CountDialog(WindowManager& parWindowManager); + CountDialog(MWBase::WindowManager& parWindowManager); void open(const std::string& item, const std::string& message, const int maxCount); typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp index e66f54326..a4b6a100b 100644 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ b/apps/openmw/mwgui/cursorreplace.cpp @@ -16,4 +16,5 @@ CursorReplace::CursorReplace() OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_dresize2.png", 45); OEngine::Render::Atlas::createFromFile("atlas1.cfg", "mwgui1", "textures\\"); + OEngine::Render::Atlas::createFromFile("mainmenu.cfg", "mwgui2", "textures\\"); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 55bd49beb..4342b1130 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -1,6 +1,5 @@ #include "dialogue.hpp" -#include #include #include @@ -10,10 +9,11 @@ #include #include "../mwbase/environment.hpp" -#include "../mwdialogue/dialoguemanager.hpp" +#include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "dialogue_history.hpp" -#include "window_manager.hpp" #include "widgets.hpp" #include "list.hpp" #include "tradewindow.hpp" @@ -42,8 +42,8 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su } -DialogueWindow::DialogueWindow(WindowManager& parWindowManager) - : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager) +DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_dialogue_window.layout", parWindowManager) , mEnabled(true) , mShowTrade(false) { @@ -51,9 +51,9 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) center(); //History view - getWidget(history, "History"); - history->setOverflowToTheLeft(true); - history->setMaxTextLength(1000000); + getWidget(mHistory, "History"); + mHistory->setOverflowToTheLeft(true); + mHistory->setMaxTextLength(1000000); Widget* eventbox; //An EditBox cannot receive mouse click events, so we use an @@ -63,36 +63,36 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); //Topics list - getWidget(topicsList, "TopicsList"); - topicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + getWidget(mTopicsList, "TopicsList"); + mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); MyGUI::ButtonPtr byeButton; getWidget(byeButton, "ByeButton"); byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); - getWidget(pDispositionBar, "Disposition"); - getWidget(pDispositionText,"DispositionText"); + getWidget(mDispositionBar, "Disposition"); + getWidget(mDispositionText,"DispositionText"); static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); } void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) { - ISubWidgetText* t = history->getClient()->getSubWidgetText(); + ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); if(t == nullptr) return; const IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); size_t cursorPosition = t->getCursorPosition(lastPressed); - MyGUI::UString color = history->getColorAtPos(cursorPosition); + MyGUI::UString color = mHistory->getColorAtPos(cursorPosition); if (!mEnabled && color == "#572D21") MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); if(color != "#B29154") { - UString key = history->getColorTextAt(cursorPosition); + UString key = mHistory->getColorTextAt(cursorPosition); if(color == "#686EBA") MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); if(color == "#572D21") MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); @@ -101,15 +101,15 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) void DialogueWindow::onWindowResize(MyGUI::Window* _sender) { - topicsList->adjustSize(); + mTopicsList->adjustSize(); } void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (history->getVScrollPosition() - _rel*0.3 < 0) - history->setVScrollPosition(0); + if (mHistory->getVScrollPosition() - _rel*0.3 < 0) + mHistory->setVScrollPosition(0); else - history->setVScrollPosition(history->getVScrollPosition() - _rel*0.3); + mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3); } void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) @@ -136,40 +136,40 @@ void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) { mEnabled = true; mPtr = actor; - topicsList->setEnabled(true); + mTopicsList->setEnabled(true); setTitle(npcName); - topicsList->clear(); - history->eraseText(0,history->getTextLength()); + mTopicsList->clear(); + mHistory->eraseText(0,mHistory->getTextLength()); updateOptions(); } void DialogueWindow::setKeywords(std::list keyWords) { - topicsList->clear(); + mTopicsList->clear(); bool anyService = mShowTrade; if (mShowTrade) - topicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarter")->str); + mTopicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarter")->str); if (anyService) - topicsList->addSeparator(); + mTopicsList->addSeparator(); for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) { - topicsList->addItem(*it); + mTopicsList->addItem(*it); } - topicsList->adjustSize(); + mTopicsList->adjustSize(); } void DialogueWindow::removeKeyword(std::string keyWord) { - if(topicsList->hasItem(keyWord)) + if(mTopicsList->hasItem(keyWord)) { - topicsList->removeItem(keyWord); + mTopicsList->removeItem(keyWord); } - topicsList->adjustSize(); + mTopicsList->adjustSize(); } void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) @@ -206,9 +206,9 @@ void addColorInString(std::string& str, const std::string& keyword,std::string c std::string DialogueWindow::parseText(std::string text) { bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) - for(unsigned int i = 0;igetItemCount();i++) + for(unsigned int i = 0;igetItemCount();i++) { - std::string keyWord = topicsList->getItemNameAt(i); + std::string keyWord = mTopicsList->getItemNameAt(i); if (separatorReached && keyWord != "") addColorInString(text,keyWord,"#686EBA","#B29154"); else @@ -219,7 +219,7 @@ std::string DialogueWindow::parseText(std::string text) void DialogueWindow::addText(std::string text) { - history->addDialogText("#B29154"+parseText(text)+"#B29154"); + mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); } void DialogueWindow::addTitle(std::string text) @@ -227,37 +227,37 @@ void DialogueWindow::addTitle(std::string text) // This is called from the dialogue manager, so text is // case-smashed - thus we have to retrieve the correct case // of the text through the topic list. - for (size_t i=0; igetItemCount(); ++i) + for (size_t i=0; igetItemCount(); ++i) { - std::string item = topicsList->getItemNameAt(i); + std::string item = mTopicsList->getItemNameAt(i); if (lower_string(item) == text) text = item; } - history->addDialogHeading(text); + mHistory->addDialogHeading(text); } void DialogueWindow::askQuestion(std::string question) { - history->addDialogText("#572D21"+question+"#B29154"+" "); + mHistory->addDialogText("#572D21"+question+"#B29154"+" "); } void DialogueWindow::updateOptions() { //Clear the list of topics - topicsList->clear(); - history->eraseText(0,history->getTextLength()); + mTopicsList->clear(); + mHistory->eraseText(0, mHistory->getTextLength()); - pDispositionBar->setProgressRange(100); - pDispositionBar->setProgressPosition(40); - pDispositionText->eraseText(0,pDispositionText->getTextLength()); - pDispositionText->addText("#B29154"+std::string("40/100")+"#B29154"); + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(40); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+std::string("40/100")+"#B29154"); } void DialogueWindow::goodbye() { - history->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGoodbye")->str); - topicsList->setEnabled(false); + mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGoodbye")->str); + mTopicsList->setEnabled(false); mEnabled = false; } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index aa66cd579..e7f2b076c 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -19,7 +19,7 @@ namespace MWGui /* This file contains the dialouge window - Layout is defined by resources/mygui/openmw_dialogue_window_layout.xml. + Layout is defined by resources/mygui/openmw_dialogue_window.layout. */ namespace MWGui @@ -29,7 +29,7 @@ namespace MWGui class DialogueWindow: public WindowBase, public ReferenceInterface { public: - DialogueWindow(WindowManager& parWindowManager); + DialogueWindow(MWBase::WindowManager& parWindowManager); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; @@ -73,10 +73,10 @@ namespace MWGui bool mEnabled; - DialogueHistory* history; - Widgets::MWList* topicsList; - MyGUI::ProgressPtr pDispositionBar; - MyGUI::EditPtr pDispositionText; + DialogueHistory* mHistory; + Widgets::MWList* mTopicsList; + MyGUI::ProgressPtr mDispositionBar; + MyGUI::EditPtr mDispositionText; }; } #endif diff --git a/apps/openmw/mwgui/dialogue_history.cpp b/apps/openmw/mwgui/dialogue_history.cpp index cd34ee119..f72f199ea 100644 --- a/apps/openmw/mwgui/dialogue_history.cpp +++ b/apps/openmw/mwgui/dialogue_history.cpp @@ -1,9 +1,10 @@ #include "dialogue_history.hpp" -#include "window_manager.hpp" + +#include "../mwbase/windowmanager.hpp" + #include "widgets.hpp" #include "components/esm_store/store.hpp" -#include #include #include @@ -72,4 +73,3 @@ void DialogueHistory::addDialogText(const UString& parText) addText(parText); addText("\n"); } - diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 95d66eb81..bdbb316b0 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -7,41 +7,44 @@ #include #include "../mwbase/environment.hpp" -#include "../mwsound/soundmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/class.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/player.hpp" +#include "../mwgui/widgets.hpp" + #include "inventorywindow.hpp" -#include "window_manager.hpp" #include "container.hpp" #include "console.hpp" using namespace MWGui; HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) - : Layout("openmw_hud_layout.xml") + : Layout("openmw_hud.layout") , health(NULL) , magicka(NULL) , stamina(NULL) - , weapImage(NULL) - , spellImage(NULL) - , weapStatus(NULL) - , spellStatus(NULL) - , effectBox(NULL) - , effect1(NULL) - , minimap(NULL) - , compass(NULL) - , crosshair(NULL) + , mWeapImage(NULL) + , mSpellImage(NULL) + , mWeapStatus(NULL) + , mSpellStatus(NULL) + , mEffectBox(NULL) + , mEffect1(NULL) + , mMinimap(NULL) + , mCompass(NULL) + , mCrosshair(NULL) , fpsbox(NULL) , fpscounter(NULL) , trianglecounter(NULL) , batchcounter(NULL) - , hmsBaseLeft(0) - , weapBoxBaseLeft(0) - , spellBoxBaseLeft(0) - , effectBoxBaseRight(0) - , minimapBoxBaseRight(0) + , mHealthManaStaminaBaseLeft(0) + , mWeapBoxBaseLeft(0) + , mSpellBoxBaseLeft(0) + , mEffectBoxBaseRight(0) + , mMinimapBoxBaseRight(0) , mDragAndDrop(dragAndDrop) , mCellNameTimer(0.0f) , mCellNameBox(NULL) @@ -58,7 +61,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) getWidget(magicka, "Magicka"); getWidget(stamina, "Stamina"); - hmsBaseLeft = mHealthFrame->getLeft(); + mHealthManaStaminaBaseLeft = mHealthFrame->getLeft(); MyGUI::Widget *healthFrame, *magickaFrame, *fatigueFrame; getWidget(healthFrame, "HealthFrame"); @@ -71,33 +74,33 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); // Item and spell images and status bars - getWidget(weapBox, "WeapBox"); - getWidget(weapImage, "WeapImage"); - getWidget(weapStatus, "WeapStatus"); - weapBoxBaseLeft = weapBox->getLeft(); - weapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); + getWidget(mWeapBox, "WeapBox"); + getWidget(mWeapImage, "WeapImage"); + getWidget(mWeapStatus, "WeapStatus"); + mWeapBoxBaseLeft = mWeapBox->getLeft(); + mWeapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); - getWidget(spellBox, "SpellBox"); - getWidget(spellImage, "SpellImage"); - getWidget(spellStatus, "SpellStatus"); - spellBoxBaseLeft = spellBox->getLeft(); - spellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); + getWidget(mSpellBox, "SpellBox"); + getWidget(mSpellImage, "SpellImage"); + getWidget(mSpellStatus, "SpellStatus"); + mSpellBoxBaseLeft = mSpellBox->getLeft(); + mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); - getWidget(effectBox, "EffectBox"); - getWidget(effect1, "Effect1"); - effectBoxBaseRight = viewSize.width - effectBox->getRight(); - effectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); + getWidget(mEffectBox, "EffectBox"); + getWidget(mEffect1, "Effect1"); + mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); + mEffectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); - getWidget(minimapBox, "MiniMapBox"); - minimapBoxBaseRight = viewSize.width - minimapBox->getRight(); - minimapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); - getWidget(minimap, "MiniMap"); - getWidget(compass, "Compass"); + getWidget(mMinimapBox, "MiniMapBox"); + mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); + mMinimapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + getWidget(mMinimap, "MiniMap"); + getWidget(mCompass, "Compass"); getWidget(mCellNameBox, "CellName"); getWidget(mWeaponSpellBox, "WeaponSpellName"); - getWidget(crosshair, "Crosshair"); + getWidget(mCrosshair, "Crosshair"); setFpsLevel(fpsLevel); @@ -106,7 +109,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) setEffect("icons\\s\\tx_s_chameleon.dds"); - LocalMapBase::init(minimap, compass, this); + LocalMapBase::init(mMinimap, mCompass, this); mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); @@ -143,19 +146,19 @@ void HUD::setFPS(float fps) fpscounter->setCaption(boost::lexical_cast((int)fps)); } -void HUD::setTriangleCount(size_t count) +void HUD::setTriangleCount(unsigned int count) { trianglecounter->setCaption(boost::lexical_cast(count)); } -void HUD::setBatchCount(size_t count) +void HUD::setBatchCount(unsigned int count) { batchcounter->setCaption(boost::lexical_cast(count)); } void HUD::setEffect(const char *img) { - effect1->setImageTexture(img); + mEffect1->setImageTexture(img); } void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) @@ -198,10 +201,10 @@ void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellV { int weapDx = 0, spellDx = 0; if (!hmsVisible) - spellDx = weapDx = weapBoxBaseLeft - hmsBaseLeft; + spellDx = weapDx = mWeapBoxBaseLeft - mHealthManaStaminaBaseLeft; if (!weapVisible) - spellDx += spellBoxBaseLeft - weapBoxBaseLeft; + spellDx += mSpellBoxBaseLeft - mWeapBoxBaseLeft; mWeaponVisible = weapVisible; mSpellVisible = spellVisible; @@ -211,10 +214,10 @@ void HUD::setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellV health->setVisible(hmsVisible); stamina->setVisible(hmsVisible); magicka->setVisible(hmsVisible); - weapBox->setPosition(weapBoxBaseLeft - weapDx, weapBox->getTop()); - weapBox->setVisible(weapVisible); - spellBox->setPosition(spellBoxBaseLeft - spellDx, spellBox->getTop()); - spellBox->setVisible(spellVisible); + mWeapBox->setPosition(mWeapBoxBaseLeft - weapDx, mWeapBox->getTop()); + mWeapBox->setVisible(weapVisible); + mSpellBox->setPosition(mSpellBoxBaseLeft - spellDx, mSpellBox->getTop()); + mSpellBox->setVisible(spellVisible); } void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible) @@ -224,12 +227,12 @@ void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible // effect box can have variable width -> variable left coordinate int effectsDx = 0; if (!minimapBoxVisible) - effectsDx = (viewSize.width - minimapBoxBaseRight) - (viewSize.width - effectBoxBaseRight); + effectsDx = (viewSize.width - mMinimapBoxBaseRight) - (viewSize.width - mEffectBoxBaseRight); mMapVisible = minimapBoxVisible; - minimapBox->setVisible(minimapBoxVisible); - effectBox->setPosition((viewSize.width - effectBoxBaseRight) - effectBox->getWidth() + effectsDx, effectBox->getTop()); - effectBox->setVisible(effectBoxVisible); + mMinimapBox->setVisible(minimapBoxVisible); + mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); + mEffectBox->setVisible(effectBoxVisible); } void HUD::onWorldClicked(MyGUI::Widget* _sender) @@ -239,7 +242,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) // drop item into the gameworld MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - MWWorld::World* world = MWBase::Environment::get().getWorld(); + MWBase::World* world = MWBase::Environment::get().getWorld(); MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); @@ -282,7 +285,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) { object = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle); } - catch (std::exception& e) + catch (std::exception& /* e */) { return; } @@ -308,7 +311,7 @@ void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) float mouseX = cursorPosition.left / float(viewSize.width); float mouseY = cursorPosition.top / float(viewSize.height); - MWWorld::World* world = MWBase::Environment::get().getWorld(); + MWBase::World* world = MWBase::Environment::get().getWorld(); // if we can't drop the object at the wanted position, show the "drop on ground" cursor. bool canDrop = world->canPlaceObject(mouseX, mouseY); @@ -391,14 +394,14 @@ void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) mWeaponSpellBox->setVisible(true); } - spellStatus->setProgressRange(100); - spellStatus->setProgressPosition(successChancePercent); + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(successChancePercent); - if (spellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0)); + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - spellBox->setUserString("ToolTipType", "Spell"); - spellBox->setUserString("Spell", spellId); + mSpellBox->setUserString("ToolTipType", "Spell"); + mSpellBox->setUserString("Spell", spellId); // use the icon of the first effect const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(spell->effects.list.front().effectID); @@ -407,7 +410,7 @@ void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) icon.insert(slashPos+1, "b_"); icon = std::string("icons\\") + icon; Widgets::fixTexturePath(icon); - spellImage->setImageTexture(icon); + mSpellImage->setImageTexture(icon); } void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) @@ -421,17 +424,17 @@ void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) mWeaponSpellBox->setVisible(true); } - spellStatus->setProgressRange(100); - spellStatus->setProgressPosition(chargePercent); + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(chargePercent); - if (spellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0)); + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - spellBox->setUserString("ToolTipType", "ItemPtr"); - spellBox->setUserData(item); + mSpellBox->setUserString("ToolTipType", "ItemPtr"); + mSpellBox->setUserData(item); - spellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = spellImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = mSpellImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) , MyGUI::Align::Stretch); std::string path = std::string("icons\\"); @@ -452,14 +455,14 @@ void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) mWeaponSpellBox->setVisible(true); } - weapBox->setUserString("ToolTipType", "ItemPtr"); - weapBox->setUserData(item); + mWeapBox->setUserString("ToolTipType", "ItemPtr"); + mWeapBox->setUserData(item); - weapStatus->setProgressRange(100); - weapStatus->setProgressPosition(durabilityPercent); + mWeapStatus->setProgressRange(100); + mWeapStatus->setProgressPosition(durabilityPercent); - if (weapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(weapImage->getChildAt(0)); + if (mWeapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); std::string path = std::string("icons\\"); path+=MWWorld::Class::get(item).getInventoryIcon(item); @@ -467,14 +470,14 @@ void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) if (MWWorld::Class::get(item).getEnchantment(item) != "") { - weapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = weapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) , MyGUI::Align::Stretch); itemBox->setImageTexture(path); itemBox->setNeedMouseFocus(false); } else - weapImage->setImageTexture(path); + mWeapImage->setImageTexture(path); } void HUD::unsetSelectedSpell() @@ -488,12 +491,12 @@ void HUD::unsetSelectedSpell() mWeaponSpellBox->setVisible(true); } - if (spellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(spellImage->getChildAt(0)); - spellStatus->setProgressRange(100); - spellStatus->setProgressPosition(0); - spellImage->setImageTexture(""); - spellBox->clearUserStrings(); + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(0); + mSpellImage->setImageTexture(""); + mSpellBox->clearUserStrings(); } void HUD::unsetSelectedWeapon() @@ -507,10 +510,10 @@ void HUD::unsetSelectedWeapon() mWeaponSpellBox->setVisible(true); } - if (weapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(weapImage->getChildAt(0)); - weapStatus->setProgressRange(100); - weapStatus->setProgressPosition(0); - weapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); - weapBox->clearUserStrings(); + if (mWeapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); + mWeapStatus->setProgressRange(100); + mWeapStatus->setProgressPosition(0); + mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); + mWeapBox->clearUserStrings(); } diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 0bfe5c20f..485c788fc 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -16,8 +16,8 @@ namespace MWGui void setEffect(const char *img); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); - void setTriangleCount(size_t count); - void setBatchCount(size_t count); + void setTriangleCount(unsigned int count); + void setBatchCount(unsigned int count); void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); void setFpsLevel(const int level); @@ -37,14 +37,14 @@ namespace MWGui MyGUI::ProgressPtr health, magicka, stamina; MyGUI::Widget* mHealthFrame; - MyGUI::Widget *weapBox, *spellBox; - MyGUI::ImageBox *weapImage, *spellImage; - MyGUI::ProgressPtr weapStatus, spellStatus; - MyGUI::Widget *effectBox, *minimapBox; - MyGUI::ImageBox* effect1; - MyGUI::ScrollView* minimap; - MyGUI::ImageBox* compass; - MyGUI::ImageBox* crosshair; + MyGUI::Widget *mWeapBox, *mSpellBox; + MyGUI::ImageBox *mWeapImage, *mSpellImage; + MyGUI::ProgressPtr mWeapStatus, mSpellStatus; + MyGUI::Widget *mEffectBox, *mMinimapBox; + MyGUI::ImageBox* mEffect1; + MyGUI::ScrollView* mMinimap; + MyGUI::ImageBox* mCompass; + MyGUI::ImageBox* mCrosshair; MyGUI::TextBox* mCellNameBox; MyGUI::TextBox* mWeaponSpellBox; @@ -55,9 +55,9 @@ namespace MWGui private: // bottom left elements - int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft; + int mHealthManaStaminaBaseLeft, mWeapBoxBaseLeft, mSpellBoxBaseLeft; // bottom right elements - int minimapBoxBaseRight, effectBoxBaseRight; + int mMinimapBoxBaseRight, mEffectBoxBaseRight; DragAndDrop* mDragAndDrop; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index a26a958bd..7b68f7b6d 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -3,22 +3,22 @@ #include #include #include -#include -#include +#include #include -#include "../mwclass/container.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/player.hpp" -#include "../mwbase/environment.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/actiontake.hpp" -#include "../mwsound/soundmanager.hpp" +#include "../mwworld/inventorystore.hpp" -#include "window_manager.hpp" #include "widgets.hpp" #include "bookwindow.hpp" #include "scrollwindow.hpp" @@ -40,9 +40,9 @@ namespace namespace MWGui { - InventoryWindow::InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) + InventoryWindow::InventoryWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) - , WindowPinnableBase("openmw_inventory_window_layout.xml", parWindowManager) + , WindowPinnableBase("openmw_inventory_window.layout", parWindowManager) , mTrading(false) { static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); @@ -171,8 +171,8 @@ namespace MWGui /// \todo scripts boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); - - action->execute(); + + action->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this is necessary for books/scrolls: if they are already in the player's inventory, // the "Take" button should not be visible. @@ -307,6 +307,9 @@ namespace MWGui && (type != typeid(ESM::Potion).name())) return; + if (MWWorld::Class::get(object).getName(object) == "") // objects without name presented to user can never be picked up + return; + // sound std::string sound = MWWorld::Class::get(object).getUpSoundId(object); MWBase::Environment::get().getSoundManager()->playSound(sound, 1, 1); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 82da3efea..fbdb79977 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -9,7 +9,7 @@ namespace MWGui class InventoryWindow : public ContainerBase, public WindowPinnableBase { public: - InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + InventoryWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop); virtual void open(); diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 7f9000bc7..597c27c6d 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -1,10 +1,12 @@ #include "journalwindow.hpp" -#include "window_manager.hpp" -#include "../mwdialogue/journal.hpp" -#include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" -#include "../mwsound/soundmanager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/journal.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwdialogue/journalentry.hpp" namespace { @@ -79,9 +81,9 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) } -MWGui::JournalWindow::JournalWindow (WindowManager& parWindowManager) - : WindowBase("openmw_journal_layout.xml", parWindowManager) - , lastPos(0) +MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_journal.layout", parWindowManager) + , mLastPos(0) , mVisible(false) { //setCoord(0,0,498, 342); @@ -145,19 +147,19 @@ void MWGui::JournalWindow::open() { if(left) { - leftPages.push_back(*it); + mLeftPages.push_back(*it); } else { - rightPages.push_back(*it); + mRightPages.push_back(*it); } left = !left; } - if(!left) rightPages.push_back(""); + if(!left) mRightPages.push_back(""); - mPageNumber = leftPages.size()-1; - displayLeftText(leftPages[mPageNumber]); - displayRightText(rightPages[mPageNumber]); + mPageNumber = mLeftPages.size()-1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); } else @@ -181,13 +183,13 @@ void MWGui::JournalWindow::displayRightText(std::string text) void MWGui::JournalWindow::notifyNextPage(MyGUI::WidgetPtr _sender) { - if(mPageNumber < int(leftPages.size())-1) + if(mPageNumber < int(mLeftPages.size())-1) { std::string nextSound = "book page2"; MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); mPageNumber = mPageNumber + 1; - displayLeftText(leftPages[mPageNumber]); - displayRightText(rightPages[mPageNumber]); + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); } } @@ -198,7 +200,7 @@ void MWGui::JournalWindow::notifyPrevPage(MyGUI::WidgetPtr _sender) std::string prevSound = "book page"; MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0); mPageNumber = mPageNumber - 1; - displayLeftText(leftPages[mPageNumber]); - displayRightText(rightPages[mPageNumber]); + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); } } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cacdb9414..fc05bbdbc 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -10,12 +10,10 @@ namespace MWGui { - class WindowManager; - class JournalWindow : public WindowBase { public: - JournalWindow(WindowManager& parWindowManager); + JournalWindow(MWBase::WindowManager& parWindowManager); void open(); virtual void setVisible(bool visible); // only used to play close sound @@ -31,17 +29,17 @@ namespace MWGui void notifyNextPage(MyGUI::WidgetPtr _sender); void notifyPrevPage(MyGUI::WidgetPtr _sender); - static const int lineHeight; + static const int sLineHeight; - MyGUI::WidgetPtr skillAreaWidget, skillClientWidget; - MyGUI::ScrollBar* skillScrollerWidget; - int lastPos, clientHeight; + MyGUI::WidgetPtr mSkillAreaWidget, mSkillClientWidget; + MyGUI::ScrollBar* mSkillScrollerWidget; + int mLastPos, mClientHeight; MyGUI::EditPtr mLeftTextWidget; MyGUI::EditPtr mRightTextWidget; MyGUI::ButtonPtr mPrevBtn; MyGUI::ButtonPtr mNextBtn; - std::vector leftPages; - std::vector rightPages; + std::vector mLeftPages; + std::vector mRightPages; int mPageNumber; //store the number of the current left page bool mVisible; }; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp new file mode 100644 index 000000000..e98b75e9b --- /dev/null +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -0,0 +1,84 @@ +#include "mainmenu.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + +namespace MWGui +{ + + MainMenu::MainMenu(int w, int h) + : OEngine::GUI::Layout("openmw_mainmenu.layout") + , mButtonBox(0) + { + onResChange(w,h); + } + + void MainMenu::onResChange(int w, int h) + { + setCoord(0,0,w,h); + + int height = 64 * 3; + + if (mButtonBox) + MyGUI::Gui::getInstance ().destroyWidget(mButtonBox); + + mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(w/2 - 64, h/2 - height/2, 128, height), MyGUI::Align::Default); + int curH = 0; + + mReturn = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); + mReturn->setImageResource ("Menu_Return"); + mReturn->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::returnToGame); + curH += 64; + + + /* + mNewGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); + mNewGame->setImageResource ("Menu_NewGame"); + curH += 64; + + mLoadGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); + mLoadGame->setImageResource ("Menu_LoadGame"); + curH += 64; + + + mSaveGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); + mSaveGame->setImageResource ("Menu_SaveGame"); + curH += 64; + */ + + mOptions = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); + mOptions->setImageResource ("Menu_Options"); + mOptions->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::showOptions); + curH += 64; + + /* + mCredits = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); + mCredits->setImageResource ("Menu_Credits"); + curH += 64; + */ + + mExitGame = mButtonBox->createWidget ("ButtonImage", MyGUI::IntCoord(0, curH, 128, 64), MyGUI::Align::Default); + mExitGame->setImageResource ("Menu_ExitGame"); + mExitGame->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::exitGame); + curH += 64; + } + + void MainMenu::returnToGame(MyGUI::Widget* sender) + { + MWBase::Environment::get().getWindowManager ()->removeGuiMode (GM_MainMenu); + } + + void MainMenu::showOptions(MyGUI::Widget* sender) + { + MWBase::Environment::get().getWindowManager ()->pushGuiMode (GM_Settings); + } + + void MainMenu::exitGame(MyGUI::Widget* sender) + { + Ogre::Root::getSingleton ().queueEndRendering (); + } + +} diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index b32f2d900..fd583d187 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -6,11 +6,24 @@ namespace MWGui class MainMenu : public OEngine::GUI::Layout { public: - MainMenu(int w, int h) - : Layout("openmw_mainmenu_layout.xml") - { - setCoord(0,0,w,h); - } + MainMenu(int w, int h); + + void onResChange(int w, int h); + + private: + MyGUI::Button* mReturn; + MyGUI::Button* mNewGame; + MyGUI::Button* mLoadGame; + MyGUI::Button* mSaveGame; + MyGUI::Button* mOptions; + MyGUI::Button* mCredits; + MyGUI::Button* mExitGame; + + MyGUI::Widget* mButtonBox; + + void returnToGame(MyGUI::Widget* sender); + void showOptions(MyGUI::Widget* sender); + void exitGame(MyGUI::Widget* sender); }; } diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index a51b66e2b..1ffedaac4 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -1,5 +1,6 @@ #include "map_window.hpp" -#include "window_manager.hpp" + +#include "../mwbase/windowmanager.hpp" #include @@ -154,8 +155,8 @@ void LocalMapBase::setPlayerDir(const float x, const float y) // ------------------------------------------------------------------------------------------ -MapWindow::MapWindow(WindowManager& parWindowManager) : - MWGui::WindowPinnableBase("openmw_map_window_layout.xml", parWindowManager), +MapWindow::MapWindow(MWBase::WindowManager& parWindowManager) : + MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager), mGlobal(false) { setCoord(500,0,320,300); diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index 8d3392b82..447c16901 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -45,11 +45,11 @@ namespace MWGui class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase { public: - MapWindow(WindowManager& parWindowManager); + MapWindow(MWBase::WindowManager& parWindowManager); virtual ~MapWindow(){} void setCellName(const std::string& cellName); - + private: void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index ca04af830..b660af7dd 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -2,7 +2,7 @@ using namespace MWGui; -MessageBoxManager::MessageBoxManager (WindowManager *windowManager) +MessageBoxManager::MessageBoxManager (MWBase::WindowManager *windowManager) { mWindowManager = windowManager; // defines @@ -147,9 +147,9 @@ int MessageBoxManager::readPressedButton () MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) - : Layout("openmw_messagebox_layout.xml") + : Layout("openmw_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) - , cMessage(message) + , mMessage(message) { // defines mFixedWidth = 300; @@ -160,7 +160,7 @@ MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::strin getWidget(mMessageWidget, "message"); mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->setCaptionWithReplacing(cMessage); + mMessageWidget->setCaptionWithReplacing(mMessage); MyGUI::IntSize size; size.width = mFixedWidth; @@ -177,7 +177,7 @@ MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::strin size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box mMainWidget->setSize(size); - size.width -= 15; // this is to center the text (see messagebox_layout.xml, Widget type="Edit" position="-2 -3 0 0") + size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0") mMessageWidget->setSize(size); } @@ -205,7 +205,7 @@ int MessageBox::getHeight () InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : Layout("openmw_interactive_messagebox_layout.xml") + : Layout("openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { @@ -265,11 +265,8 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan if(buttonsWidth < fixedWidth) { // on one line - std::cout << "on one line" << std::endl; - if(textSize.width + 2*textPadding < buttonsWidth) { - std::cout << "width = buttonsWidth" << std::endl; mainWidgetSize.width = buttonsWidth; } else @@ -282,13 +279,9 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - std::cout << "width " << mainWidgetSize.width << " height " << mainWidgetSize.height << std::endl; - std::cout << "left " << absCoord.left << " top " << absCoord.top << std::endl; - mMainWidget->setCoord(absCoord); mMainWidget->setSize(mainWidgetSize); - MyGUI::IntCoord messageWidgetCoord; messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; messageWidgetCoord.top = textPadding; @@ -318,7 +311,6 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan else { // among each other - if(biggestButtonWidth > textSize.width) { mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; } @@ -327,8 +319,6 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan } mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; - std::cout << "biggestButtonWidth " << biggestButtonWidth << " textSize.width " << textSize.width << std::endl; - std::cout << "width " << mainWidgetSize.width << " height " << mainWidgetSize.height << std::endl; mMainWidget->setSize(mainWidgetSize); MyGUI::IntCoord absCoord; @@ -383,7 +373,6 @@ void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) } index++; } - std::cout << "Cant be possible :/" << std::endl; } int InteractiveMessageBox::readPressedButton () diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 33155b2a0..5e4c468d5 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -5,13 +5,13 @@ #include #include "window_base.hpp" -#include "window_manager.hpp" + +#include "../mwbase/windowmanager.hpp" #undef MessageBox namespace MWGui { - class InteractiveMessageBox; class MessageBoxManager; class MessageBox; @@ -25,27 +25,27 @@ namespace MWGui class MessageBoxManager { public: - MessageBoxManager (WindowManager* windowManager); + MessageBoxManager (MWBase::WindowManager* windowManager); void onFrame (float frameDuration); void createMessageBox (const std::string& message); bool createInteractiveMessageBox (const std::string& message, const std::vector& buttons); bool isInteractiveMessageBox (); - + void removeMessageBox (float time, MessageBox *msgbox); bool removeMessageBox (MessageBox *msgbox); void setMessageBoxSpeed (int speed); - + int readPressedButton (); - - WindowManager *mWindowManager; - + + MWBase::WindowManager *mWindowManager; + private: std::vector mMessageBoxes; InteractiveMessageBox* mInterMessageBoxe; std::vector mTimers; float mMessageBoxSpeed; }; - + class MessageBox : public OEngine::GUI::Layout { public: @@ -53,28 +53,28 @@ namespace MWGui void setMessage (const std::string& message); int getHeight (); void update (int height); - + bool mMarkedToDelete; - + protected: MessageBoxManager& mMessageBoxManager; int mHeight; - const std::string& cMessage; + const std::string& mMessage; MyGUI::EditPtr mMessageWidget; int mFixedWidth; int mBottomPadding; int mNextBoxPadding; }; - + class InteractiveMessageBox : public OEngine::GUI::Layout { public: InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons); void mousePressed (MyGUI::Widget* _widget); int readPressedButton (); - + bool mMarkedToDelete; - + private: MessageBoxManager& mMessageBoxManager; MyGUI::EditPtr mMessageWidget; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index dea365ac2..ceb0452fb 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -1,6 +1,5 @@ #include "race.hpp" -#include #include #include @@ -9,20 +8,23 @@ #include -#include "window_manager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + #include "widgets.hpp" #include "tooltips.hpp" using namespace MWGui; using namespace Widgets; -RaceDialog::RaceDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_race_layout.xml", parWindowManager) - , genderIndex(0) - , faceIndex(0) - , hairIndex(0) - , faceCount(10) - , hairCount(14) +RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_race.layout", parWindowManager) + , mGenderIndex(0) + , mFaceIndex(0) + , mHairIndex(0) + , mFaceCount(10) + , mHairCount(14) { // Centre dialog center(); @@ -31,13 +33,13 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager) // real calls from outside the class later. setText("AppearanceT", mWindowManager.getGameSettingString("sRaceMenu1", "Appearance")); - getWidget(appearanceBox, "AppearanceBox"); + getWidget(mAppearanceBox, "AppearanceBox"); - getWidget(headRotate, "HeadRotate"); - headRotate->setScrollRange(50); - headRotate->setScrollPosition(20); - headRotate->setScrollViewPage(10); - headRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); + getWidget(mHeadRotate, "HeadRotate"); + mHeadRotate->setScrollRange(50); + mHeadRotate->setScrollPosition(20); + mHeadRotate->setScrollViewPage(10); + mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); // Set up next/previous buttons MyGUI::ButtonPtr prevButton, nextButton; @@ -61,16 +63,16 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager) nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu4", "Race")); - getWidget(raceList, "RaceList"); - raceList->setScrollVisible(true); - raceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - raceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - raceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + getWidget(mRaceList, "RaceList"); + mRaceList->setScrollVisible(true); + mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); setText("SkillsT", mWindowManager.getGameSettingString("sBonusSkillTitle", "Skill Bonus")); - getWidget(skillList, "SkillList"); + getWidget(mSkillList, "SkillList"); setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials")); - getWidget(spellPowerList, "SpellPowerList"); + getWidget(mSpellPowerList, "SpellPowerList"); MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); @@ -117,14 +119,14 @@ void RaceDialog::open() void RaceDialog::setRaceId(const std::string &raceId) { - currentRaceId = raceId; - raceList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = raceList->getItemCount(); + mCurrentRaceId = raceId; + mRaceList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mRaceList->getItemCount(); for (size_t i = 0; i < count; ++i) { - if (boost::iequals(*raceList->getItemDataAt(i), raceId)) + if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) { - raceList->setIndexSelected(i); + mRaceList->setIndexSelected(i); break; } } @@ -162,32 +164,32 @@ void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) { - genderIndex = wrap(genderIndex - 1, 2); + mGenderIndex = wrap(mGenderIndex - 1, 2); } void RaceDialog::onSelectNextGender(MyGUI::Widget*) { - genderIndex = wrap(genderIndex + 1, 2); + mGenderIndex = wrap(mGenderIndex + 1, 2); } void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) { - faceIndex = wrap(faceIndex - 1, faceCount); + mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); } void RaceDialog::onSelectNextFace(MyGUI::Widget*) { - faceIndex = wrap(faceIndex + 1, faceCount); + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); } void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) { - hairIndex = wrap(hairIndex - 1, hairCount); + mHairIndex = wrap(mHairIndex - 1, mHairCount); } void RaceDialog::onSelectNextHair(MyGUI::Widget*) { - hairIndex = wrap(hairIndex - 1, hairCount); + mHairIndex = wrap(mHairIndex - 1, mHairCount); } void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) @@ -195,11 +197,11 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) if (_index == MyGUI::ITEM_NONE) return; - const std::string *raceId = raceList->getItemDataAt(_index); - if (boost::iequals(currentRaceId, *raceId)) + const std::string *raceId = mRaceList->getItemDataAt(_index); + if (boost::iequals(mCurrentRaceId, *raceId)) return; - currentRaceId = *raceId; + mCurrentRaceId = *raceId; updateSkills(); updateSpellPowers(); } @@ -208,9 +210,9 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) void RaceDialog::updateRaces() { - raceList->removeAllItems(); + mRaceList->removeAllItems(); - const ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); ESMS::RecListT::MapType::const_iterator it = store.races.list.begin(); ESMS::RecListT::MapType::const_iterator end = store.races.list.end(); @@ -222,30 +224,30 @@ void RaceDialog::updateRaces() if (!playable) // Only display playable races continue; - raceList->addItem(race.name, it->first); - if (boost::iequals(it->first, currentRaceId)) - raceList->setIndexSelected(index); + mRaceList->addItem(race.name, it->first); + if (boost::iequals(it->first, mCurrentRaceId)) + mRaceList->setIndexSelected(index); ++index; } } void RaceDialog::updateSkills() { - for (std::vector::iterator it = skillItems.begin(); it != skillItems.end(); ++it) + for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } - skillItems.clear(); + mSkillItems.clear(); - if (currentRaceId.empty()) + if (mCurrentRaceId.empty()) return; MWSkillPtr skillWidget; const int lineHeight = 18; - MyGUI::IntCoord coord1(0, 0, skillList->getWidth(), 18); + MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18); - const ESMS::ESMStore &store = mWindowManager.getStore(); - const ESM::Race *race = store.races.find(currentRaceId); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.races.find(mCurrentRaceId); int count = sizeof(race->data.bonus)/sizeof(race->data.bonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? for (int i = 0; i < count; ++i) { @@ -253,7 +255,7 @@ void RaceDialog::updateSkills() if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes continue; - skillWidget = skillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, + skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, std::string("Skill") + boost::lexical_cast(i)); skillWidget->setWindowManager(&mWindowManager); skillWidget->setSkillNumber(skillId); @@ -261,7 +263,7 @@ void RaceDialog::updateSkills() ToolTips::createSkillToolTip(skillWidget, skillId); - skillItems.push_back(skillWidget); + mSkillItems.push_back(skillWidget); coord1.top += lineHeight; } @@ -269,34 +271,34 @@ void RaceDialog::updateSkills() void RaceDialog::updateSpellPowers() { - for (std::vector::iterator it = spellPowerItems.begin(); it != spellPowerItems.end(); ++it) + for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } - spellPowerItems.clear(); + mSpellPowerItems.clear(); - if (currentRaceId.empty()) + if (mCurrentRaceId.empty()) return; MWSpellPtr spellPowerWidget; const int lineHeight = 18; - MyGUI::IntCoord coord(0, 0, spellPowerList->getWidth(), 18); + MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18); - const ESMS::ESMStore &store = mWindowManager.getStore(); - const ESM::Race *race = store.races.find(currentRaceId); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.races.find(mCurrentRaceId); std::vector::const_iterator it = race->powers.list.begin(); std::vector::const_iterator end = race->powers.list.end(); for (int i = 0; it != end; ++it) { const std::string &spellpower = *it; - spellPowerWidget = spellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); + spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); spellPowerWidget->setWindowManager(&mWindowManager); spellPowerWidget->setSpellId(spellpower); spellPowerWidget->setUserString("ToolTipType", "Spell"); spellPowerWidget->setUserString("Spell", spellpower); - spellPowerItems.push_back(spellPowerWidget); + mSpellPowerItems.push_back(spellPowerWidget); coord.top += lineHeight; ++i; diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index bcd3b5185..3da6b0ace 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -14,7 +14,7 @@ namespace MWGui /* This file contains the dialog for choosing a race. - Layout is defined by resources/mygui/openmw_chargen_race_layout.xml. + Layout is defined by resources/mygui/openmw_chargen_race.layout. */ namespace MWGui @@ -24,7 +24,7 @@ namespace MWGui class RaceDialog : public WindowBase { public: - RaceDialog(WindowManager& parWindowManager); + RaceDialog(MWBase::WindowManager& parWindowManager); enum Gender { @@ -32,13 +32,13 @@ namespace MWGui GM_Female }; - const std::string &getRaceId() const { return currentRaceId; } - Gender getGender() const { return genderIndex == 0 ? GM_Male : GM_Female; } + const std::string &getRaceId() const { return mCurrentRaceId; } + Gender getGender() const { return mGenderIndex == 0 ? GM_Male : GM_Female; } // getFace() // getHair() void setRaceId(const std::string &raceId); - void setGender(Gender gender) { genderIndex = gender == GM_Male ? 0 : 1; } + void setGender(Gender gender) { mGenderIndex = gender == GM_Male ? 0 : 1; } // setFace() // setHair() @@ -75,20 +75,20 @@ namespace MWGui void updateSkills(); void updateSpellPowers(); - MyGUI::CanvasPtr appearanceBox; - MyGUI::ListBox* raceList; - MyGUI::ScrollBar* headRotate; + MyGUI::CanvasPtr mAppearanceBox; + MyGUI::ListBox* mRaceList; + MyGUI::ScrollBar* mHeadRotate; - MyGUI::WidgetPtr skillList; - std::vector skillItems; + MyGUI::WidgetPtr mSkillList; + std::vector mSkillItems; - MyGUI::WidgetPtr spellPowerList; - std::vector spellPowerItems; + MyGUI::WidgetPtr mSpellPowerList; + std::vector mSpellPowerItems; - int genderIndex, faceIndex, hairIndex; - int faceCount, hairCount; + int mGenderIndex, mFaceIndex, mHairIndex; + int mFaceCount, mHairCount; - std::string currentRaceId; + std::string mCurrentRaceId; }; } #endif diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index c6e710952..b1f7affb6 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -1,9 +1,10 @@ #include "referenceinterface.hpp" -#include "../mwworld/player.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" + namespace MWGui { ReferenceInterface::ReferenceInterface() @@ -11,6 +12,10 @@ namespace MWGui { } + ReferenceInterface::~ReferenceInterface() + { + } + void ReferenceInterface::checkReferenceAvailable() { if (mPtr.isEmpty()) diff --git a/apps/openmw/mwgui/referenceinterface.hpp b/apps/openmw/mwgui/referenceinterface.hpp index 40844b238..39574d0f7 100644 --- a/apps/openmw/mwgui/referenceinterface.hpp +++ b/apps/openmw/mwgui/referenceinterface.hpp @@ -13,6 +13,7 @@ namespace MWGui { public: ReferenceInterface(); + virtual ~ReferenceInterface(); void checkReferenceAvailable(); ///< closes the window, if the MW-reference has become unavailable @@ -22,7 +23,7 @@ namespace MWGui MWWorld::Ptr mPtr; private: - MWWorld::Ptr::CellStore* mCurrentPlayerCell; + MWWorld::CellStore* mCurrentPlayerCell; }; } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 97a3a6e15..8dd894c25 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -7,7 +7,10 @@ #include -#include "window_manager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + #include "widgets.hpp" #include "tooltips.hpp" @@ -17,49 +20,49 @@ using namespace MWGui; using namespace Widgets; -const int ReviewDialog::lineHeight = 18; +const int ReviewDialog::sLineHeight = 18; -ReviewDialog::ReviewDialog(WindowManager& parWindowManager) - : WindowBase("openmw_chargen_review_layout.xml", parWindowManager) - , lastPos(0) +ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_chargen_review.layout", parWindowManager) + , mLastPos(0) { // Centre dialog center(); // Setup static stats ButtonPtr button; - getWidget(nameWidget, "NameText"); + getWidget(mNameWidget, "NameText"); getWidget(button, "NameButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; - getWidget(raceWidget, "RaceText"); + getWidget(mRaceWidget, "RaceText"); getWidget(button, "RaceButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; - getWidget(classWidget, "ClassText"); + getWidget(mClassWidget, "ClassText"); getWidget(button, "ClassButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; - getWidget(birthSignWidget, "SignText"); + getWidget(mBirthSignWidget, "SignText"); getWidget(button, "SignButton"); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; // Setup dynamic stats - getWidget(health, "Health"); - health->setTitle(mWindowManager.getGameSettingString("sHealth", "")); - health->setValue(45, 45); + getWidget(mHealth, "Health"); + mHealth->setTitle(mWindowManager.getGameSettingString("sHealth", "")); + mHealth->setValue(45, 45); - getWidget(magicka, "Magicka"); - magicka->setTitle(mWindowManager.getGameSettingString("sMagic", "")); - magicka->setValue(50, 50); + getWidget(mMagicka, "Magicka"); + mMagicka->setTitle(mWindowManager.getGameSettingString("sMagic", "")); + mMagicka->setValue(50, 50); - getWidget(fatigue, "Fatigue"); - fatigue->setTitle(mWindowManager.getGameSettingString("sFatigue", "")); - fatigue->setValue(160, 160); + getWidget(mFatigue, "Fatigue"); + mFatigue->setTitle(mWindowManager.getGameSettingString("sFatigue", "")); + mFatigue->setValue(160, 160); // Setup attributes @@ -67,24 +70,24 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) for (int idx = 0; idx < ESM::Attribute::Length; ++idx) { getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); - attributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::attributeIds[idx]), attribute)); + mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::attributeIds[idx]), attribute)); attribute->setWindowManager(&mWindowManager); attribute->setAttributeId(ESM::Attribute::attributeIds[idx]); attribute->setAttributeValue(MWAttribute::AttributeValue(0, 0)); } // Setup skills - getWidget(skillAreaWidget, "Skills"); - getWidget(skillClientWidget, "SkillClient"); - getWidget(skillScrollerWidget, "SkillScroller"); - skillClientWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - skillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &ReviewDialog::onScrollChangePosition); + getWidget(mSkillAreaWidget, "Skills"); + getWidget(mSkillClientWidget, "SkillClient"); + getWidget(mSkillScrollerWidget, "SkillScroller"); + mSkillClientWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + mSkillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &ReviewDialog::onScrollChangePosition); updateScroller(); for (int i = 0; i < ESM::Skill::Length; ++i) { - skillValues.insert(std::make_pair(i, MWMechanics::Stat())); - skillWidgetMap.insert(std::make_pair(i, static_cast (0))); + mSkillValues.insert(std::make_pair(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); } static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ReviewDialog::onWindowResize); @@ -112,14 +115,14 @@ void ReviewDialog::open() void ReviewDialog::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos) { - int diff = lastPos - pos; + int diff = mLastPos - pos; // Adjust position of all widget according to difference if (diff == 0) return; - lastPos = pos; + mLastPos = pos; - std::vector::const_iterator end = skillWidgets.end(); - for (std::vector::const_iterator it = skillWidgets.begin(); it != end; ++it) + std::vector::const_iterator end = mSkillWidgets.end(); + for (std::vector::const_iterator it = mSkillWidgets.begin(); it != end; ++it) { (*it)->setCoord((*it)->getCoord() + MyGUI::IntPoint(0, diff)); } @@ -132,63 +135,63 @@ void ReviewDialog::onWindowResize(MyGUI::Window* window) void ReviewDialog::setPlayerName(const std::string &name) { - nameWidget->setCaption(name); + mNameWidget->setCaption(name); } -void ReviewDialog::setRace(const std::string &raceId_) +void ReviewDialog::setRace(const std::string &raceId) { - raceId = raceId_; - const ESM::Race *race = mWindowManager.getStore().races.search(raceId); + mRaceId = raceId; + const ESM::Race *race = MWBase::Environment::get().getWorld()->getStore().races.search(mRaceId); if (race) { - ToolTips::createRaceToolTip(raceWidget, race); - raceWidget->setCaption(race->name); + ToolTips::createRaceToolTip(mRaceWidget, race); + mRaceWidget->setCaption(race->name); } } void ReviewDialog::setClass(const ESM::Class& class_) { - klass = class_; - classWidget->setCaption(klass.name); - ToolTips::createClassToolTip(classWidget, klass); + mKlass = class_; + mClassWidget->setCaption(mKlass.name); + ToolTips::createClassToolTip(mClassWidget, mKlass); } void ReviewDialog::setBirthSign(const std::string& signId) { - birthSignId = signId; - const ESM::BirthSign *sign = mWindowManager.getStore().birthSigns.search(birthSignId); + mBirthSignId = signId; + const ESM::BirthSign *sign = MWBase::Environment::get().getWorld()->getStore().birthSigns.search(mBirthSignId); if (sign) { - birthSignWidget->setCaption(sign->name); - ToolTips::createBirthsignToolTip(birthSignWidget, birthSignId); + mBirthSignWidget->setCaption(sign->name); + ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); } } void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) { - health->setValue(value.getCurrent(), value.getModified()); + mHealth->setValue(value.getCurrent(), value.getModified()); std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - health->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); } void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) { - magicka->setValue(value.getCurrent(), value.getModified()); + mMagicka->setValue(value.getCurrent(), value.getModified()); std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - magicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); } void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) { - fatigue->setValue(value.getCurrent(), value.getModified()); + mFatigue->setValue(value.getCurrent(), value.getModified()); std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - fatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); } void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) { - std::map::iterator attr = attributeWidgets.find(static_cast(attributeId)); - if (attr == attributeWidgets.end()) + std::map::iterator attr = mAttributeWidgets.find(static_cast(attributeId)); + if (attr == mAttributeWidgets.end()) return; attr->second->setAttributeValue(value); @@ -196,8 +199,8 @@ void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const M void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value) { - skillValues[skillId] = value; - MyGUI::TextBox* widget = skillWidgetMap[skillId]; + mSkillValues[skillId] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; if (widget) { float modified = value.getModified(), base = value.getBase(); @@ -216,20 +219,20 @@ void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanic void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) { - majorSkills = major; - minorSkills = minor; + mMajorSkills = major; + mMinorSkills = minor; // Update misc skills with the remaining skills not in major or minor std::set skillSet; std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); boost::array::const_iterator end = ESM::Skill::skillIds.end(); - miscSkills.clear(); + mMiscSkills.clear(); for (boost::array::const_iterator it = ESM::Skill::skillIds.begin(); it != end; ++it) { int skill = *it; if (skillSet.find(skill) == skillSet.end()) - miscSkills.push_back(skill); + mMiscSkills.push_back(skill); } updateSkillArea(); @@ -237,10 +240,10 @@ void ReviewDialog::configureSkills(const std::vector& major, const std::vec void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { - MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); + MyGUI::ImageBox* separator = mSkillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); separator->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - skillWidgets.push_back(separator); + mSkillWidgets.push_back(separator); coord1.top += separator->getHeight(); coord2.top += separator->getHeight(); @@ -248,13 +251,13 @@ void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2 void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { - MyGUI::TextBox* groupWidget = skillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default); + MyGUI::TextBox* groupWidget = mSkillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default); groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); groupWidget->setCaption(label); - skillWidgets.push_back(groupWidget); + mSkillWidgets.push_back(groupWidget); - coord1.top += lineHeight; - coord2.top += lineHeight; + coord1.top += sLineHeight; + coord2.top += sLineHeight; } MyGUI::TextBox* ReviewDialog::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) @@ -262,20 +265,20 @@ MyGUI::TextBox* ReviewDialog::addValueItem(const std::string& text, const std::s MyGUI::TextBox* skillNameWidget; MyGUI::TextBox* skillValueWidget; - skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default); + skillNameWidget = mSkillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Default); skillNameWidget->setCaption(text); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); + skillValueWidget = mSkillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - skillWidgets.push_back(skillNameWidget); - skillWidgets.push_back(skillValueWidget); + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); - coord1.top += lineHeight; - coord2.top += lineHeight; + coord1.top += sLineHeight; + coord2.top += sLineHeight; return skillValueWidget; } @@ -284,20 +287,20 @@ void ReviewDialog::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyG { MyGUI::TextBox* skillNameWidget; - skillNameWidget = skillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget = mSkillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); skillNameWidget->setCaption(text); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - skillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillNameWidget); - coord1.top += lineHeight; - coord2.top += lineHeight; + coord1.top += sLineHeight; + coord2.top += sLineHeight; } void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { // Add a line separator if there are items above - if (!skillWidgets.empty()) + if (!mSkillWidgets.empty()) { addSeparator(coord1, coord2); } @@ -312,7 +315,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId continue; assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESMS::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = skillValues.find(skillId)->second; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; float base = stat.getBase(); float modified = stat.getModified(); @@ -325,44 +328,44 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId for (int i=0; i<2; ++i) { - ToolTips::createSkillToolTip(skillWidgets[skillWidgets.size()-1-i], skillId); + ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size()-1-i], skillId); } - skillWidgetMap[skillId] = widget; + mSkillWidgetMap[skillId] = widget; } } void ReviewDialog::updateSkillArea() { - for (std::vector::iterator it = skillWidgets.begin(); it != skillWidgets.end(); ++it) + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } - skillWidgets.clear(); + mSkillWidgets.clear(); const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, skillClientWidget->getWidth() - (10 + valueSize), 18); + MyGUI::IntCoord coord1(10, 0, mSkillClientWidget->getWidth() - (10 + valueSize), 18); MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); - if (!majorSkills.empty()) - addSkills(majorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); - if (!minorSkills.empty()) - addSkills(minorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); - if (!miscSkills.empty()) - addSkills(miscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - clientHeight = coord1.top; + mClientHeight = coord1.top; updateScroller(); } void ReviewDialog::updateScroller() { - skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0)); - skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0)); - if (clientHeight != 0) - skillScrollerWidget->setTrackSize( (skillAreaWidget->getHeight() / float(clientHeight)) * skillScrollerWidget->getLineSize() ); + mSkillScrollerWidget->setScrollRange(std::max(mClientHeight - mSkillClientWidget->getHeight(), 0)); + mSkillScrollerWidget->setScrollPage(std::max(mSkillClientWidget->getHeight() - sLineHeight, 0)); + if (mClientHeight != 0) + mSkillScrollerWidget->setTrackSize( (mSkillAreaWidget->getHeight() / float(mClientHeight)) * mSkillScrollerWidget->getLineSize() ); } // widget controls @@ -399,12 +402,12 @@ void ReviewDialog::onBirthSignClicked(MyGUI::Widget* _sender) void ReviewDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (skillScrollerWidget->getScrollPosition() - _rel*0.3 < 0) - skillScrollerWidget->setScrollPosition(0); - else if (skillScrollerWidget->getScrollPosition() - _rel*0.3 > skillScrollerWidget->getScrollRange()-1) - skillScrollerWidget->setScrollPosition(skillScrollerWidget->getScrollRange()-1); + if (mSkillScrollerWidget->getScrollPosition() - _rel*0.3 < 0) + mSkillScrollerWidget->setScrollPosition(0); + else if (mSkillScrollerWidget->getScrollPosition() - _rel*0.3 > mSkillScrollerWidget->getScrollRange()-1) + mSkillScrollerWidget->setScrollPosition(mSkillScrollerWidget->getScrollRange()-1); else - skillScrollerWidget->setScrollPosition(skillScrollerWidget->getScrollPosition() - _rel*0.3); + mSkillScrollerWidget->setScrollPosition(mSkillScrollerWidget->getScrollPosition() - _rel*0.3); - onScrollChangePosition(skillScrollerWidget, skillScrollerWidget->getScrollPosition()); + onScrollChangePosition(mSkillScrollerWidget, mSkillScrollerWidget->getScrollPosition()); } diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 6118168d5..f0bde6ecd 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -12,7 +12,7 @@ namespace MWGui /* This file contains the dialog for reviewing the generated character. -Layout is defined by resources/mygui/openmw_chargen_review_layout.xml. +Layout is defined by resources/mygui/openmw_chargen_review.layout. */ namespace MWGui @@ -30,7 +30,7 @@ namespace MWGui }; typedef std::vector SkillList; - ReviewDialog(WindowManager& parWindowManager); + ReviewDialog(MWBase::WindowManager& parWindowManager); void setPlayerName(const std::string &name); void setRace(const std::string &raceId); @@ -82,23 +82,23 @@ namespace MWGui void onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onWindowResize(MyGUI::Window* window); - static const int lineHeight; + static const int sLineHeight; - MyGUI::TextBox *nameWidget, *raceWidget, *classWidget, *birthSignWidget; - MyGUI::WidgetPtr skillAreaWidget, skillClientWidget; - MyGUI::ScrollBar* skillScrollerWidget; - int lastPos, clientHeight; + MyGUI::TextBox *mNameWidget, *mRaceWidget, *mClassWidget, *mBirthSignWidget; + MyGUI::WidgetPtr mSkillAreaWidget, mSkillClientWidget; + MyGUI::ScrollBar* mSkillScrollerWidget; + int mLastPos, mClientHeight; - Widgets::MWDynamicStatPtr health, magicka, fatigue; + Widgets::MWDynamicStatPtr mHealth, mMagicka, mFatigue; - std::map attributeWidgets; + std::map mAttributeWidgets; - SkillList majorSkills, minorSkills, miscSkills; - std::map > skillValues; - std::map skillWidgetMap; - std::string name, raceId, birthSignId; - ESM::Class klass; - std::vector skillWidgets; //< Skills and other information + SkillList mMajorSkills, mMinorSkills, mMiscSkills; + std::map > mSkillValues; + std::map mSkillWidgetMap; + std::string mName, mRaceId, mBirthSignId; + ESM::Class mKlass; + std::vector mSkillWidgets; //< Skills and other information }; } #endif diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 92b18d953..ff83b0e3e 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -1,17 +1,19 @@ #include "scrollwindow.hpp" #include "../mwbase/environment.hpp" -#include "../mwinput/inputmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/actiontake.hpp" -#include "../mwsound/soundmanager.hpp" +#include "../mwworld/player.hpp" #include "formatting.hpp" -#include "window_manager.hpp" using namespace MWGui; -ScrollWindow::ScrollWindow (WindowManager& parWindowManager) : - WindowBase("openmw_scroll_layout.xml", parWindowManager) +ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) : + WindowBase("openmw_scroll.layout", parWindowManager) { getWidget(mTextView, "TextView"); @@ -31,8 +33,7 @@ void ScrollWindow::open (MWWorld::Ptr scroll) mScroll = scroll; - ESMS::LiveCellRef *ref = - mScroll.get(); + MWWorld::LiveCellRef *ref = mScroll.get(); BookTextParser parser; MyGUI::IntSize size = parser.parse(ref->base->text, mTextView, 390); @@ -61,10 +62,10 @@ void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); MWWorld::ActionTake take(mScroll); - take.execute(); + take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mWindowManager.removeGuiMode(GM_Scroll); } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index d58596b4b..b8f52fb65 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -10,7 +10,7 @@ namespace MWGui class ScrollWindow : public WindowBase { public: - ScrollWindow (WindowManager& parWindowManager); + ScrollWindow (MWBase::WindowManager& parWindowManager); void open (MWWorld::Ptr scroll); void setTakeButtonShow(bool show); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index eafbd3462..f6597a64e 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -5,15 +5,19 @@ #include #include +#include +#include #include #include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" -#include "../mwsound/soundmanager.hpp" -#include "../mwinput/inputmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/inputmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwrender/renderingmanager.hpp" -#include "window_manager.hpp" #include "confirmationdialog.hpp" namespace @@ -39,12 +43,46 @@ namespace else return "Trilinear"; } + + void parseResolution (int &x, int &y, const std::string& str) + { + std::vector split; + boost::algorithm::split (split, str, boost::is_any_of("@(x")); + assert (split.size() >= 2); + boost::trim(split[0]); + boost::trim(split[1]); + x = boost::lexical_cast (split[0]); + y = boost::lexical_cast (split[1]); + } + + bool sortResolutions (std::pair left, std::pair right) + { + if (left.first == right.first) + return left.second > right.second; + return left.first > right.first; + } + + std::string getAspect (int x, int y) + { + int gcd = boost::math::gcd (x, y); + int xaspect = x / gcd; + int yaspect = y / gcd; + // special case: 8 : 5 is usually referred to as 16:10 + if (xaspect == 8 && yaspect == 5) + return "16 : 10"; + return boost::lexical_cast(xaspect) + " : " + boost::lexical_cast(yaspect); + } + + std::string hlslGlsl () + { + return (Ogre::Root::getSingleton ().getRenderSystem ()->getName ().find("OpenGL") != std::string::npos) ? "glsl" : "hlsl"; + } } namespace MWGui { - SettingsWindow::SettingsWindow(WindowManager& parWindowManager) : - WindowBase("openmw_settings_window_layout.xml", parWindowManager) + SettingsWindow::SettingsWindow(MWBase::WindowManager& parWindowManager) : + WindowBase("openmw_settings_window.layout", parWindowManager) { getWidget(mOkButton, "OkButton"); getWidget(mResolutionList, "ResolutionList"); @@ -68,8 +106,19 @@ namespace MWGui getWidget(mReflectObjectsButton, "ReflectObjectsButton"); getWidget(mReflectActorsButton, "ReflectActorsButton"); getWidget(mReflectTerrainButton, "ReflectTerrainButton"); + getWidget(mShadersButton, "ShadersButton"); + getWidget(mShadowsEnabledButton, "ShadowsEnabledButton"); + getWidget(mShadowsLargeDistance, "ShadowsLargeDistance"); + getWidget(mShadowsTextureSize, "ShadowsTextureSize"); + getWidget(mActorShadows, "ActorShadows"); + getWidget(mStaticsShadows, "StaticsShadows"); + getWidget(mMiscShadows, "MiscShadows"); + getWidget(mShadowsDebug, "ShadowsDebug"); + getWidget(mUnderwaterButton, "UnderwaterButton"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked); + mUnderwaterButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mShadersButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadersToggled); mFullscreenButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mWaterShaderButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mReflectObjectsButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -85,6 +134,14 @@ namespace MWGui mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mAnisotropySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mShadowsEnabledButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mShadowsLargeDistance->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mShadowsTextureSize->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShadowTextureSize); + mActorShadows->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mStaticsShadows->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mMiscShadows->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mShadowsDebug->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); + mMasterVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mVoiceVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mEffectsVolumeSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); @@ -99,11 +156,25 @@ namespace MWGui // fill resolution list Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); - const Ogre::StringVector& videoModes = rs->getConfigOptions()["Video Mode"].possibleValues; + Ogre::StringVector videoModes = rs->getConfigOptions()["Video Mode"].possibleValues; + std::vector < std::pair > resolutions; for (Ogre::StringVector::const_iterator it=videoModes.begin(); it!=videoModes.end(); ++it) { - mResolutionList->addItem(*it); + + int resX, resY; + parseResolution (resX, resY, *it); + resolutions.push_back(std::make_pair(resX, resY)); + } + std::sort(resolutions.begin(), resolutions.end(), sortResolutions); + for (std::vector < std::pair >::const_iterator it=resolutions.begin(); + it!=resolutions.end(); ++it) + { + std::string str = boost::lexical_cast(it->first) + " x " + boost::lexical_cast(it->second) + + " (" + getAspect(it->first,it->second) + ")"; + + if (mResolutionList->findItemIndexWith(str) == MyGUI::ITEM_NONE) + mResolutionList->addItem(str); } // read settings @@ -123,7 +194,6 @@ namespace MWGui std::string tf = Settings::Manager::getString("texture filtering", "General"); mTextureFilteringButton->setCaption(textureFilteringToStr(tf)); mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(Settings::Manager::getInt("anisotropy", "General")) + ")"); - mAnisotropyBox->setVisible(tf == "anisotropic"); float val = (Settings::Manager::getFloat("max viewing distance", "Viewing distance")-sViewDistMin)/(sViewDistMax-sViewDistMin); int viewdist = (mViewDistanceSlider->getScrollRange()-1) * val; @@ -136,9 +206,27 @@ namespace MWGui mVoiceVolumeSlider->setScrollPosition(Settings::Manager::getFloat("voice volume", "Sound") * (mVoiceVolumeSlider->getScrollRange()-1)); mWaterShaderButton->setCaptionWithReplacing(Settings::Manager::getBool("shader", "Water") ? "#{sOn}" : "#{sOff}"); - mReflectObjectsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect objects", "Water") ? "#{sOn}" : "#{sOff}"); + mReflectObjectsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect statics", "Water") ? "#{sOn}" : "#{sOff}"); mReflectActorsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect actors", "Water") ? "#{sOn}" : "#{sOff}"); mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}"); + mUnderwaterButton->setCaptionWithReplacing(Settings::Manager::getBool("underwater effect", "Water") ? "#{sOn}" : "#{sOff}"); + + mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); + mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); + mShadowsEnabledButton->setCaptionWithReplacing(Settings::Manager::getBool("enabled", "Shadows") ? "#{sOn}" : "#{sOff}"); + mActorShadows->setCaptionWithReplacing(Settings::Manager::getBool("actor shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); + mStaticsShadows->setCaptionWithReplacing(Settings::Manager::getBool("statics shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); + mMiscShadows->setCaptionWithReplacing(Settings::Manager::getBool("misc shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); + mShadowsDebug->setCaptionWithReplacing(Settings::Manager::getBool("debug", "Shadows") ? "#{sOn}" : "#{sOff}"); + + std::string shaders; + if (!Settings::Manager::getBool("shaders", "Objects")) + shaders = "off"; + else + { + shaders = Settings::Manager::getString("shader mode", "General"); + } + mShadersButton->setCaption (shaders); if (!MWRender::RenderingManager::waterShaderSupported()) { @@ -148,6 +236,12 @@ namespace MWGui mReflectTerrainButton->setEnabled(false); } + if (shaders == "off") + { + mUnderwaterButton->setEnabled (false); + mShadowsEnabledButton->setEnabled(false); + } + mFullscreenButton->setCaptionWithReplacing(Settings::Manager::getBool("fullscreen", "Video") ? "#{sOn}" : "#{sOff}"); mVSyncButton->setCaptionWithReplacing(Settings::Manager::getBool("vsync", "Video") ? "#{sOn}": "#{sOff}"); mFPSButton->setCaptionWithReplacing(fpsLevelToStr(Settings::Manager::getInt("fps", "HUD"))); @@ -168,19 +262,14 @@ namespace MWGui dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); dialog->eventCancelClicked.clear(); - dialog->eventCancelClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); + dialog->eventCancelClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionCancel); } void SettingsWindow::onResolutionAccept() { std::string resStr = mResolutionList->getItemNameAt(mResolutionList->getIndexSelected()); - size_t xPos = resStr.find("x"); - std::string resXStr = resStr.substr(0, xPos-1); - Ogre::StringUtil::trim(resXStr); - std::string resYStr = resStr.substr(xPos+2, resStr.size()-(xPos+2)); - Ogre::StringUtil::trim(resYStr); - int resX = boost::lexical_cast(resXStr); - int resY = boost::lexical_cast(resYStr); + int resX, resY; + parseResolution (resX, resY, resStr); Settings::Manager::setInt("resolution x", "Video", resX); Settings::Manager::setInt("resolution y", "Video", resY); @@ -194,6 +283,25 @@ namespace MWGui mResolutionList->setIndexSelected(MyGUI::ITEM_NONE); } + void SettingsWindow::onShadowTextureSize(MyGUI::Widget* _sender) + { + std::string size = mShadowsTextureSize->getCaption(); + + if (size == "512") + size = "1024"; + else if (size == "1024") + size = "2048"; + else if (size == "2048") + size = "4096"; + else + size = "512"; + + mShadowsTextureSize->setCaption(size); + + Settings::Manager::setString("texture size", "Shadows", size); + apply(); + } + void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) { std::string on = mWindowManager.getGameSettingString("sOn", "On"); @@ -217,13 +325,8 @@ namespace MWGui for (unsigned int i=0; igetItemCount(); ++i) { std::string resStr = mResolutionList->getItemNameAt(i); - size_t xPos = resStr.find("x"); - std::string resXStr = resStr.substr(0, xPos-1); - Ogre::StringUtil::trim(resXStr); - std::string resYStr = resStr.substr(xPos+2, resStr.size()-(xPos+2)); - Ogre::StringUtil::trim(resYStr); - int resX = boost::lexical_cast(resXStr); - int resY = boost::lexical_cast(resYStr); + int resX, resY; + parseResolution (resX, resY, resStr); if (resX == Settings::Manager::getInt("resolution x", "Video") && resY == Settings::Manager::getInt("resolution y", "Video")) @@ -253,6 +356,10 @@ namespace MWGui { if (_sender == mWaterShaderButton) Settings::Manager::setBool("shader", "Water", newState); + else if (_sender == mUnderwaterButton) + { + Settings::Manager::setBool("underwater effect", "Water", newState); + } else if (_sender == mReflectObjectsButton) { Settings::Manager::setBool("reflect misc", "Water", newState); @@ -263,11 +370,77 @@ namespace MWGui Settings::Manager::setBool("reflect actors", "Water", newState); else if (_sender == mReflectTerrainButton) Settings::Manager::setBool("reflect terrain", "Water", newState); + else if (_sender == mShadowsEnabledButton) + Settings::Manager::setBool("enabled", "Shadows", newState); + else if (_sender == mShadowsLargeDistance) + Settings::Manager::setBool("split", "Shadows", newState); + else if (_sender == mActorShadows) + Settings::Manager::setBool("actor shadows", "Shadows", newState); + else if (_sender == mStaticsShadows) + Settings::Manager::setBool("statics shadows", "Shadows", newState); + else if (_sender == mMiscShadows) + Settings::Manager::setBool("misc shadows", "Shadows", newState); + else if (_sender == mShadowsDebug) + Settings::Manager::setBool("debug", "Shadows", newState); apply(); } } + void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) + { + std::string val = static_cast(_sender)->getCaption(); + if (val == "off") + { + val = hlslGlsl(); + } + else if (val == hlslGlsl()) + val = "cg"; + else + val = "off"; + + static_cast(_sender)->setCaption(val); + + if (val == "off") + { + Settings::Manager::setBool("shaders", "Objects", false); + + // water shader not supported with object shaders off + mWaterShaderButton->setCaptionWithReplacing("#{sOff}"); + mUnderwaterButton->setCaptionWithReplacing("#{sOff}"); + mWaterShaderButton->setEnabled(false); + mReflectObjectsButton->setEnabled(false); + mReflectActorsButton->setEnabled(false); + mReflectTerrainButton->setEnabled(false); + mUnderwaterButton->setEnabled(false); + Settings::Manager::setBool("shader", "Water", false); + Settings::Manager::setBool("underwater effect", "Water", false); + + // shadows not supported + mShadowsEnabledButton->setEnabled(false); + mShadowsEnabledButton->setCaptionWithReplacing("#{sOff}"); + Settings::Manager::setBool("enabled", "Shadows", false); + } + else + { + Settings::Manager::setBool("shaders", "Objects", true); + Settings::Manager::setString("shader mode", "General", val); + + // re-enable + if (MWRender::RenderingManager::waterShaderSupported()) + { + mWaterShaderButton->setEnabled(true); + mReflectObjectsButton->setEnabled(true); + mReflectActorsButton->setEnabled(true); + mReflectTerrainButton->setEnabled(true); + } + mUnderwaterButton->setEnabled(true); + mShadowsEnabledButton->setEnabled(true); + } + + apply(); + } + void SettingsWindow::onFpsToggled(MyGUI::Widget* _sender) { int newLevel = (Settings::Manager::getInt("fps", "HUD") + 1) % 3; @@ -290,7 +463,6 @@ namespace MWGui next = "none"; mTextureFilteringButton->setCaption(textureFilteringToStr(next)); - mAnisotropyBox->setVisible(next == "anisotropic"); Settings::Manager::setString("texture filtering", "General", next); apply(); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index e3827c7b0..ca11b6f9c 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -13,7 +13,7 @@ namespace MWGui class SettingsWindow : public WindowBase { public: - SettingsWindow(WindowManager& parWindowManager); + SettingsWindow(MWBase::WindowManager& parWindowManager); private: static int const sFovMin = 30; @@ -42,6 +42,16 @@ namespace MWGui MyGUI::Button* mReflectObjectsButton; MyGUI::Button* mReflectActorsButton; MyGUI::Button* mReflectTerrainButton; + MyGUI::Button* mShadersButton; + MyGUI::Button* mUnderwaterButton; + + MyGUI::Button* mShadowsEnabledButton; + MyGUI::Button* mShadowsLargeDistance; + MyGUI::Button* mShadowsTextureSize; + MyGUI::Button* mActorShadows; + MyGUI::Button* mStaticsShadows; + MyGUI::Button* mMiscShadows; + MyGUI::Button* mShadowsDebug; // audio MyGUI::ScrollBar* mMasterVolumeSlider; @@ -59,9 +69,11 @@ namespace MWGui void onResolutionAccept(); void onResolutionCancel(); + void onShadersToggled(MyGUI::Widget* _sender); + void onShadowTextureSize(MyGUI::Widget* _sender); + void apply(); }; } #endif - diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d34ce68d9..8754f5d10 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -4,16 +4,20 @@ #include #include -#include "../mwworld/world.hpp" +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/player.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwbase/environment.hpp" + #include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" -#include "../mwsound/soundmanager.hpp" -#include "window_manager.hpp" #include "inventorywindow.hpp" #include "confirmationdialog.hpp" @@ -38,8 +42,8 @@ namespace namespace MWGui { - SpellWindow::SpellWindow(WindowManager& parWindowManager) - : WindowPinnableBase("openmw_spell_window_layout.xml", parWindowManager) + SpellWindow::SpellWindow(MWBase::WindowManager& parWindowManager) + : WindowPinnableBase("openmw_spell_window.layout", parWindowManager) , mHeight(0) , mWidth(0) { @@ -76,7 +80,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); - MWMechanics::Spells& spells = stats.mSpells; + MWMechanics::Spells& spells = stats.getSpells(); // the following code switches between selected enchanted item and selected spell (only one of these // can be active at a time) @@ -144,9 +148,11 @@ namespace MWGui powers.push_back(*it); it = spellList.erase(it); } - else if (spell->data.type == ESM::Spell::ST_Ability) + else if (spell->data.type == ESM::Spell::ST_Ability + || spell->data.type == ESM::Spell::ST_Blight + || spell->data.type == ESM::Spell::ST_Curse + || spell->data.type == ESM::Spell::ST_Disease) { - // abilities are always active and don't show in the spell window. it = spellList.erase(it); } else @@ -326,7 +332,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); - MWMechanics::Spells& spells = stats.mSpells; + MWMechanics::Spells& spells = stats.getSpells(); MWWorld::Ptr item = *_sender->getUserData(); // retrieve ContainerStoreIterator to the item @@ -390,7 +396,7 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWWorld::InventoryStore& store = MWWorld::Class::get(player).getInventoryStore(player); - MWMechanics::Spells& spells = stats.mSpells; + MWMechanics::Spells& spells = stats.getSpells(); if (MyGUI::InputManager::getInstance().isShiftPressed()) { @@ -444,7 +450,7 @@ namespace MWGui { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); - MWMechanics::Spells& spells = stats.mSpells; + MWMechanics::Spells& spells = stats.getSpells(); if (spells.getSelectedSpell() == mSpellToDelete) { diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 87e4783ba..caa67fd74 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -8,7 +8,7 @@ namespace MWGui class SpellWindow : public WindowPinnableBase { public: - SpellWindow(WindowManager& parWindowManager); + SpellWindow(MWBase::WindowManager& parWindowManager); void updateSpells(); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 3584af7c7..32dac71de 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -6,36 +6,40 @@ #include -#include "../mwmechanics/mechanicsmanager.hpp" -#include "../mwworld/world.hpp" -#include "../mwworld/player.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/npcstats.hpp" -#include "window_manager.hpp" #include "tooltips.hpp" using namespace MWGui; -const int StatsWindow::lineHeight = 18; +const int StatsWindow::sLineHeight = 18; -StatsWindow::StatsWindow (WindowManager& parWindowManager) - : WindowPinnableBase("openmw_stats_window_layout.xml", parWindowManager) - , skillAreaWidget(NULL) - , skillClientWidget(NULL) - , skillScrollerWidget(NULL) - , lastPos(0) - , clientHeight(0) - , majorSkills() - , minorSkills() - , miscSkills() - , skillValues() - , skillWidgetMap() - , factionWidgetMap() +StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) + : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) + , mSkillAreaWidget(NULL) + , mSkillClientWidget(NULL) + , mSkillScrollerWidget(NULL) + , mLastPos(0) + , mClientHeight(0) + , mMajorSkills() + , mMinorSkills() + , mMiscSkills() + , mSkillValues() + , mSkillWidgetMap() + , mFactionWidgetMap() , mFactions() - , birthSignId() - , reputation(0) - , bounty(0) - , skillWidgets() + , mBirthSignId() + , mReputation(0) + , mBounty(0) + , mSkillWidgets() , mChanged(true) { setCoord(0,0,498, 342); @@ -53,27 +57,27 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) { 0, 0 } }; - const ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); for (int i=0; names[i][0]; ++i) { setText (names[i][0], store.gameSettings.find (names[i][1])->str); } - getWidget(skillAreaWidget, "Skills"); - getWidget(skillClientWidget, "SkillClient"); - getWidget(skillScrollerWidget, "SkillScroller"); + getWidget(mSkillAreaWidget, "Skills"); + getWidget(mSkillClientWidget, "SkillClient"); + getWidget(mSkillScrollerWidget, "SkillScroller"); getWidget(mLeftPane, "LeftPane"); getWidget(mRightPane, "RightPane"); - skillClientWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillClientWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - skillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &StatsWindow::onScrollChangePosition); + mSkillScrollerWidget->eventScrollChangePosition += MyGUI::newDelegate(this, &StatsWindow::onScrollChangePosition); updateScroller(); for (int i = 0; i < ESM::Skill::Length; ++i) { - skillValues.insert(std::pair >(i, MWMechanics::Stat())); - skillWidgetMap.insert(std::pair(i, nullptr)); + mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::pair(i, nullptr)); } MyGUI::WindowPtr t = static_cast(mMainWidget); @@ -82,14 +86,14 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) void StatsWindow::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos) { - int diff = lastPos - pos; + int diff = mLastPos - pos; // Adjust position of all widget according to difference if (diff == 0) return; - lastPos = pos; + mLastPos = pos; - std::vector::const_iterator end = skillWidgets.end(); - for (std::vector::const_iterator it = skillWidgets.begin(); it != end; ++it) + std::vector::const_iterator end = mSkillWidgets.end(); + for (std::vector::const_iterator it = mSkillWidgets.begin(); it != end; ++it) { (*it)->setCoord((*it)->getCoord() + MyGUI::IntPoint(0, diff)); } @@ -97,14 +101,14 @@ void StatsWindow::onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos) void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - if (skillScrollerWidget->getScrollPosition() - _rel*0.3 < 0) - skillScrollerWidget->setScrollPosition(0); - else if (skillScrollerWidget->getScrollPosition() - _rel*0.3 > skillScrollerWidget->getScrollRange()-1) - skillScrollerWidget->setScrollPosition(skillScrollerWidget->getScrollRange()-1); + if (mSkillScrollerWidget->getScrollPosition() - _rel*0.3 < 0) + mSkillScrollerWidget->setScrollPosition(0); + else if (mSkillScrollerWidget->getScrollPosition() - _rel*0.3 > mSkillScrollerWidget->getScrollRange()-1) + mSkillScrollerWidget->setScrollPosition(mSkillScrollerWidget->getScrollRange()-1); else - skillScrollerWidget->setScrollPosition(skillScrollerWidget->getScrollPosition() - _rel*0.3); + mSkillScrollerWidget->setScrollPosition(mSkillScrollerWidget->getScrollPosition() - _rel*0.3); - onScrollChangePosition(skillScrollerWidget, skillScrollerWidget->getScrollPosition()); + onScrollChangePosition(mSkillScrollerWidget, mSkillScrollerWidget->getScrollPosition()); } void StatsWindow::onWindowResize(MyGUI::Window* window) @@ -221,8 +225,8 @@ void StatsWindow::setValue (const std::string& id, int value) void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) { - skillValues[parSkill] = value; - MyGUI::TextBox* widget = skillWidgetMap[(int)parSkill]; + mSkillValues[parSkill] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; if (widget) { float modified = value.getModified(), base = value.getBase(); @@ -240,20 +244,20 @@ void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechani void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) { - majorSkills = major; - minorSkills = minor; + mMajorSkills = major; + mMinorSkills = minor; // Update misc skills with the remaining skills not in major or minor std::set skillSet; std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); boost::array::const_iterator end = ESM::Skill::skillIds.end(); - miscSkills.clear(); + mMiscSkills.clear(); for (boost::array::const_iterator it = ESM::Skill::skillIds.begin(); it != end; ++it) { int skill = *it; if (skillSet.find(skill) == skillSet.end()) - miscSkills.push_back(skill); + mMiscSkills.push_back(skill); } updateSkillArea(); @@ -267,7 +271,7 @@ void StatsWindow::onFrame () MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - setFactions(PCstats.mFactionRank); + setFactions(PCstats.getFactionRanks()); setBirthSign(MWBase::Environment::get().getWorld()->getPlayer().getBirthsign()); @@ -286,20 +290,20 @@ void StatsWindow::setFactions (const FactionList& factions) void StatsWindow::setBirthSign (const std::string& signId) { - if (signId != birthSignId) + if (signId != mBirthSignId) { - birthSignId = signId; + mBirthSignId = signId; mChanged = true; } } void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { - MyGUI::ImageBox* separator = skillClientWidget->createWidget("MW_HLine", + MyGUI::ImageBox* separator = mSkillClientWidget->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); separator->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - skillWidgets.push_back(separator); + mSkillWidgets.push_back(separator); coord1.top += separator->getHeight(); coord2.top += separator->getHeight(); @@ -307,35 +311,35 @@ void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { - MyGUI::TextBox* groupWidget = skillClientWidget->createWidget("SandBrightText", + MyGUI::TextBox* groupWidget = mSkillClientWidget->createWidget("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); groupWidget->setCaption(label); groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - skillWidgets.push_back(groupWidget); + mSkillWidgets.push_back(groupWidget); - coord1.top += lineHeight; - coord2.top += lineHeight; + coord1.top += sLineHeight; + coord2.top += sLineHeight; } MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox *skillNameWidget, *skillValueWidget; - skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + skillNameWidget = mSkillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); skillNameWidget->setCaption(text); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); + skillValueWidget = mSkillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - skillWidgets.push_back(skillNameWidget); - skillWidgets.push_back(skillValueWidget); + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); - coord1.top += lineHeight; - coord2.top += lineHeight; + coord1.top += sLineHeight; + coord2.top += sLineHeight; return skillValueWidget; } @@ -344,14 +348,14 @@ MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &co { MyGUI::TextBox* skillNameWidget; - skillNameWidget = skillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget = mSkillClientWidget->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); skillNameWidget->setCaption(text); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - skillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillNameWidget); - coord1.top += lineHeight; - coord2.top += lineHeight; + coord1.top += sLineHeight; + coord2.top += sLineHeight; return skillNameWidget; } @@ -359,7 +363,7 @@ MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &co void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { // Add a line separator if there are items above - if (!skillWidgets.empty()) + if (!mSkillWidgets.empty()) { addSeparator(coord1, coord2); } @@ -374,17 +378,17 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, continue; assert(skillId >= 0 && skillId < ESM::Skill::Length); const std::string &skillNameId = ESMS::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = skillValues.find(skillId)->second; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; float base = stat.getBase(); float modified = stat.getModified(); int progressPercent = (modified - float(static_cast(modified))) * 100; - const ESM::Skill* skill = mWindowManager.getStore().skills.search(skillId); + const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().skills.search(skillId); assert(skill); std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; - const ESM::Attribute* attr = mWindowManager.getStore().attributes.search(skill->data.attribute); + const ESM::Attribute* attr = MWBase::Environment::get().getWorld()->getStore().attributes.search(skill->data.attribute); assert(attr); std::string state = "normal"; @@ -397,18 +401,18 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, for (int i=0; i<2; ++i) { - skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->description); - skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->name + "}"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); - skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->description); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->name + "}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); } - skillWidgetMap[skillId] = widget; + mSkillWidgetMap[skillId] = widget; } } @@ -416,30 +420,30 @@ void StatsWindow::updateSkillArea() { mChanged = false; - for (std::vector::iterator it = skillWidgets.begin(); it != skillWidgets.end(); ++it) + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } - skillWidgets.clear(); + mSkillWidgets.clear(); - skillScrollerWidget->setScrollPosition(0); - onScrollChangePosition(skillScrollerWidget, 0); - clientHeight = 0; + mSkillScrollerWidget->setScrollPosition(0); + onScrollChangePosition(mSkillScrollerWidget, 0); + mClientHeight = 0; const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, skillClientWidget->getWidth() - (10 + valueSize), 18); + MyGUI::IntCoord coord1(10, 0, mSkillClientWidget->getWidth() - (10 + valueSize), 18); MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); - if (!majorSkills.empty()) - addSkills(majorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); - if (!minorSkills.empty()) - addSkills(minorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); - if (!miscSkills.empty()) - addSkills(miscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - const ESMS::ESMStore &store = mWindowManager.getStore(); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); // race tooltip const ESM::Race* playerRace = store.races.find (MWBase::Environment::get().getWorld()->getPlayer().getRace()); @@ -460,7 +464,7 @@ void StatsWindow::updateSkillArea() if (!mFactions.empty()) { // Add a line separator if there are items above - if (!skillWidgets.empty()) + if (!mSkillWidgets.empty()) addSeparator(coord1, coord2); addGroup(mWindowManager.getGameSettingString("sFaction", "Faction"), coord1, coord2); @@ -481,8 +485,8 @@ void StatsWindow::updateSkillArea() text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->ranks[it->second+1]; ESM::RankData rankData = faction->data.rankData[it->second+1]; - const ESM::Attribute* attr1 = mWindowManager.getStore().attributes.search(faction->data.attribute1); - const ESM::Attribute* attr2 = mWindowManager.getStore().attributes.search(faction->data.attribute2); + const ESM::Attribute* attr1 = MWBase::Environment::get().getWorld()->getStore().attributes.search(faction->data.attribute1); + const ESM::Attribute* attr2 = MWBase::Environment::get().getWorld()->getStore().attributes.search(faction->data.attribute2); assert(attr1 && attr2); text += "\n#BF9959#{" + attr1->name + "}: " + boost::lexical_cast(rankData.attribute1) @@ -492,7 +496,7 @@ void StatsWindow::updateSkillArea() text += "\n#BF9959"; for (int i=0; i<6; ++i) { - const ESM::Skill* skill = mWindowManager.getStore().skills.search(faction->data.skillID[i]); + const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().skills.search(faction->data.skillID[i]); assert(skill); text += "#{"+ESM::Skill::sSkillNameIds[faction->data.skillID[i]]+"}"; if (i<5) @@ -513,53 +517,53 @@ void StatsWindow::updateSkillArea() } } - if (!birthSignId.empty()) + if (!mBirthSignId.empty()) { // Add a line separator if there are items above - if (!skillWidgets.empty()) + if (!mSkillWidgets.empty()) addSeparator(coord1, coord2); addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); - const ESM::BirthSign *sign = store.birthSigns.find(birthSignId); + const ESM::BirthSign *sign = store.birthSigns.find(mBirthSignId); MyGUI::Widget* w = addItem(sign->name, coord1, coord2); - ToolTips::createBirthsignToolTip(w, birthSignId); + ToolTips::createBirthsignToolTip(w, mBirthSignId); } // Add a line separator if there are items above - if (!skillWidgets.empty()) + if (!mSkillWidgets.empty()) addSeparator(coord1, coord2); addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(reputation)), "normal", coord1, coord2); + boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { - skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); } - + addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(bounty)), "normal", coord1, coord2); + boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { - skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); } - clientHeight = coord1.top; + mClientHeight = coord1.top; updateScroller(); } void StatsWindow::updateScroller() { - skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0)); - skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0)); - if (clientHeight != 0) - skillScrollerWidget->setTrackSize( (skillAreaWidget->getHeight() / float(clientHeight)) * skillScrollerWidget->getLineSize() ); + mSkillScrollerWidget->setScrollRange(std::max(mClientHeight - mSkillClientWidget->getHeight(), 0)); + mSkillScrollerWidget->setScrollPage(std::max(mSkillClientWidget->getHeight() - sLineHeight, 0)); + if (mClientHeight != 0) + mSkillScrollerWidget->setTrackSize( (mSkillAreaWidget->getHeight() / float(mClientHeight)) * mSkillScrollerWidget->getLineSize() ); } void StatsWindow::onPinToggled() diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 10b794cc0..a46ab7531 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -22,7 +22,7 @@ namespace MWGui typedef std::vector SkillList; - StatsWindow(WindowManager& parWindowManager); + StatsWindow(MWBase::WindowManager& parWindowManager); /// automatically updates all the data in the stats window, but only if it has changed. void onFrame(); @@ -38,8 +38,8 @@ namespace MWGui void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); void configureSkills (const SkillList& major, const SkillList& minor); - void setReputation (int reputation) { this->reputation = reputation; } - void setBounty (int bounty) { this->bounty = bounty; } + void setReputation (int reputation) { this->mReputation = reputation; } + void setBounty (int bounty) { this->mBounty = bounty; } void updateSkillArea(); private: @@ -57,23 +57,23 @@ namespace MWGui void onWindowResize(MyGUI::Window* window); void onMouseWheel(MyGUI::Widget* _sender, int _rel); - static const int lineHeight; + static const int sLineHeight; MyGUI::Widget* mLeftPane; MyGUI::Widget* mRightPane; - MyGUI::WidgetPtr skillAreaWidget, skillClientWidget; - MyGUI::ScrollBar* skillScrollerWidget; - int lastPos, clientHeight; + MyGUI::WidgetPtr mSkillAreaWidget, mSkillClientWidget; + MyGUI::ScrollBar* mSkillScrollerWidget; + int mLastPos, mClientHeight; - SkillList majorSkills, minorSkills, miscSkills; - std::map > skillValues; - std::map skillWidgetMap; - std::map factionWidgetMap; + SkillList mMajorSkills, mMinorSkills, mMiscSkills; + std::map > mSkillValues; + std::map mSkillWidgetMap; + std::map mFactionWidgetMap; FactionList mFactions; ///< Stores a list of factions and the current rank - std::string birthSignId; - int reputation, bounty; - std::vector skillWidgets; //< Skills and other information + std::string mBirthSignId; + int mReputation, mBounty; + std::vector mSkillWidgets; //< Skills and other information bool mChanged; @@ -82,4 +82,3 @@ namespace MWGui }; } #endif - diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 7d84a9b9f..802cd3063 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -1,23 +1,24 @@ #include "text_input.hpp" -#include "window_manager.hpp" + +#include "../mwbase/windowmanager.hpp" using namespace MWGui; -TextInputDialog::TextInputDialog(WindowManager& parWindowManager) - : WindowBase("openmw_text_input_layout.xml", parWindowManager) +TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) + : WindowBase("openmw_text_input.layout", parWindowManager) { // Centre dialog center(); - getWidget(textEdit, "TextEdit"); - textEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); + getWidget(mTextEdit, "TextEdit"); + mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit); + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); } void TextInputDialog::setNextButtonShow(bool shown) @@ -43,7 +44,7 @@ void TextInputDialog::setTextLabel(const std::string &label) void TextInputDialog::open() { // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit); + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); setVisible(true); } diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp index fe355655f..7a3325722 100644 --- a/apps/openmw/mwgui/text_input.hpp +++ b/apps/openmw/mwgui/text_input.hpp @@ -18,10 +18,10 @@ namespace MWGui class TextInputDialog : public WindowBase { public: - TextInputDialog(WindowManager& parWindowManager); + TextInputDialog(MWBase::WindowManager& parWindowManager); - std::string getTextInput() const { return textEdit ? textEdit->getOnlyText() : ""; } - void setTextInput(const std::string &text) { if (textEdit) textEdit->setOnlyText(text); } + std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } + void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } void setNextButtonShow(bool shown); void setTextLabel(const std::string &label); @@ -32,7 +32,7 @@ namespace MWGui void onTextAccepted(MyGUI::Edit* _sender); private: - MyGUI::EditPtr textEdit; + MyGUI::EditPtr mTextEdit; }; } #endif diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7ec444168..edc787cef 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -1,20 +1,24 @@ #include "tooltips.hpp" -#include "window_manager.hpp" -#include "widgets.hpp" -#include "../mwworld/class.hpp" -#include "../mwworld/world.hpp" -#include "../mwbase/environment.hpp" - #include +#include + #include +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/class.hpp" + +#include "widgets.hpp" + using namespace MWGui; using namespace MyGUI; -ToolTips::ToolTips(WindowManager* windowManager) : - Layout("openmw_tooltips.xml") +ToolTips::ToolTips(MWBase::WindowManager* windowManager) : + Layout("openmw_tooltips.layout") , mGameMode(true) , mWindowManager(windowManager) , mFullHelp(false) @@ -77,7 +81,7 @@ void ToolTips::onFrame(float frameDuration) { mFocusObject = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle); } - catch (std::exception& e) + catch (std::exception /* & e */) { return; } @@ -392,7 +396,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) /** * \todo - * the various potion effects should appear in the tooltip depending if the player + * the various potion effects should appear in the tooltip depending if the player * has enough skill in alchemy to know about the effects of this potion. */ @@ -564,8 +568,6 @@ void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId) if (attributeId == -1) return; - const ESM::Attribute* attr = MWBase::Environment::get().getWorld()->getStore().attributes.search(attributeId); - assert(attr); std::string icon = ESM::Attribute::attributeIcons[attributeId]; std::string name = ESM::Attribute::gmstAttributeIds[attributeId]; std::string desc = ESM::Attribute::gmstAttributeDescIds[attributeId]; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 036bdfaa3..700f5f723 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -9,8 +9,6 @@ namespace MWGui { - class WindowManager; - // Info about tooltip that is supplied by the MWWorld::Class object struct ToolTipInfo { @@ -29,7 +27,7 @@ namespace MWGui class ToolTips : public OEngine::GUI::Layout { public: - ToolTips(WindowManager* windowManager); + ToolTips(MWBase::WindowManager* windowManager); void onFrame(float frameDuration); @@ -45,7 +43,7 @@ namespace MWGui void setFocusObject(const MWWorld::Ptr& focus); void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); - ///< set the screen-space position of the tooltip for focused object + ///< set the screen-space position of the tooltip for focused object static std::string getValueString(const int value, const std::string& prefix); ///< @return "prefix: value" or "" if value is 0 @@ -71,7 +69,7 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - WindowManager* mWindowManager; + MWBase::WindowManager* mWindowManager; MWWorld::Ptr mFocusObject; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index a42da60d1..8471367c6 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -3,18 +3,19 @@ #include #include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" -#include "../mwsound/soundmanager.hpp" -#include "window_manager.hpp" #include "inventorywindow.hpp" namespace MWGui { - TradeWindow::TradeWindow(WindowManager& parWindowManager) : - WindowBase("openmw_trade_window_layout.xml", parWindowManager) + TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : + WindowBase("openmw_trade_window.layout", parWindowManager) , ContainerBase(NULL) // no drag&drop , mCurrentBalance(0) { @@ -86,7 +87,7 @@ namespace MWGui offerButtonWidth, mOfferButton->getHeight()); - setCoord(400, 0, 400, 300); + setCoord(400, 0, 400, 300); static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &TradeWindow::onWindowResize); } @@ -161,7 +162,7 @@ namespace MWGui int merchantgold; if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mPtr.get(); + MWWorld::LiveCellRef* ref = mPtr.get(); if (ref->base->npdt52.gold == -10) merchantgold = ref->base->npdt12.gold; else @@ -169,7 +170,7 @@ namespace MWGui } else // ESM::Creature { - ESMS::LiveCellRef* ref = mPtr.get(); + MWWorld::LiveCellRef* ref = mPtr.get(); merchantgold = ref->base->data.gold; } if (mCurrentBalance > 0 && merchantgold < mCurrentBalance) @@ -244,7 +245,7 @@ namespace MWGui int merchantgold; if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mPtr.get(); + MWWorld::LiveCellRef* ref = mPtr.get(); if (ref->base->npdt52.gold == -10) merchantgold = ref->base->npdt12.gold; else @@ -252,7 +253,7 @@ namespace MWGui } else // ESM::Creature { - ESMS::LiveCellRef* ref = mPtr.get(); + MWWorld::LiveCellRef* ref = mPtr.get(); merchantgold = ref->base->data.gold; } @@ -289,13 +290,13 @@ namespace MWGui int services = 0; if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { - ESMS::LiveCellRef* ref = mPtr.get(); + MWWorld::LiveCellRef* ref = mPtr.get(); if (ref->base->hasAI) services = ref->base->AI.services; } else if (mPtr.getTypeName() == typeid(ESM::Creature).name()) { - ESMS::LiveCellRef* ref = mPtr.get(); + MWWorld::LiveCellRef* ref = mPtr.get(); if (ref->base->hasAI) services = ref->base->AI.services; } diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index b391fd8fa..1daeefa96 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -23,7 +23,7 @@ namespace MWGui class TradeWindow : public ContainerBase, public WindowBase { public: - TradeWindow(WindowManager& parWindowManager); + TradeWindow(MWBase::WindowManager& parWindowManager); void startTrade(MWWorld::Ptr actor); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 65de7ce0a..40ee1c7ad 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -1,9 +1,13 @@ #include "widgets.hpp" -#include "window_manager.hpp" -#include "components/esm_store/store.hpp" #include +#include "components/esm_store/store.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + #undef min #undef max @@ -27,16 +31,16 @@ void MWGui::Widgets::fixTexturePath(std::string &path) /* MWSkill */ MWSkill::MWSkill() - : manager(nullptr) - , skillId(ESM::Skill::Length) - , skillNameWidget(nullptr) - , skillValueWidget(nullptr) + : mManager(nullptr) + , mSkillId(ESM::Skill::Length) + , mSkillNameWidget(nullptr) + , mSkillValueWidget(nullptr) { } void MWSkill::setSkillId(ESM::Skill::SkillEnum skill) { - skillId = skill; + mSkillId = skill; updateWidgets(); } @@ -50,36 +54,36 @@ void MWSkill::setSkillNumber(int skill) throw new std::runtime_error("Skill number out of range"); } -void MWSkill::setSkillValue(const SkillValue& value_) +void MWSkill::setSkillValue(const SkillValue& value) { - value = value_; + mValue = value; updateWidgets(); } void MWSkill::updateWidgets() { - if (skillNameWidget && manager) + if (mSkillNameWidget && mManager) { - if (skillId == ESM::Skill::Length) + if (mSkillId == ESM::Skill::Length) { - static_cast(skillNameWidget)->setCaption(""); + static_cast(mSkillNameWidget)->setCaption(""); } else { - const std::string &name = manager->getGameSettingString(ESM::Skill::sSkillNameIds[skillId], ""); - static_cast(skillNameWidget)->setCaption(name); + const std::string &name = mManager->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); + static_cast(mSkillNameWidget)->setCaption(name); } } - if (skillValueWidget) + if (mSkillValueWidget) { - SkillValue::Type modified = value.getModified(), base = value.getBase(); - static_cast(skillValueWidget)->setCaption(boost::lexical_cast(modified)); + SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); + static_cast(mSkillValueWidget)->setCaption(boost::lexical_cast(modified)); if (modified > base) - skillValueWidget->_setWidgetState("increased"); + mSkillValueWidget->_setWidgetState("increased"); else if (modified < base) - skillValueWidget->_setWidgetState("decreased"); + mSkillValueWidget->_setWidgetState("decreased"); else - skillValueWidget->_setWidgetState("normal"); + mSkillValueWidget->_setWidgetState("normal"); } } @@ -96,14 +100,14 @@ void MWSkill::initialiseOverride() { Base::initialiseOverride(); - assignWidget(skillNameWidget, "StatName"); - assignWidget(skillValueWidget, "StatValue"); + assignWidget(mSkillNameWidget, "StatName"); + assignWidget(mSkillValueWidget, "StatValue"); MyGUI::ButtonPtr button; assignWidget(button, "StatNameButton"); if (button) { - skillNameWidget = button; + mSkillNameWidget = button; button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); } @@ -111,7 +115,7 @@ void MWSkill::initialiseOverride() assignWidget(button, "StatValueButton"); if (button) { - skillNameWidget = button; + mSkillNameWidget = button; button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); } } @@ -119,22 +123,22 @@ void MWSkill::initialiseOverride() /* MWAttribute */ MWAttribute::MWAttribute() - : manager(nullptr) - , id(-1) - , attributeNameWidget(nullptr) - , attributeValueWidget(nullptr) + : mManager(nullptr) + , mId(-1) + , mAttributeNameWidget(nullptr) + , mAttributeValueWidget(nullptr) { } void MWAttribute::setAttributeId(int attributeId) { - id = attributeId; + mId = attributeId; updateWidgets(); } -void MWAttribute::setAttributeValue(const AttributeValue& value_) +void MWAttribute::setAttributeValue(const AttributeValue& value) { - value = value_; + mValue = value; updateWidgets(); } @@ -145,11 +149,11 @@ void MWAttribute::onClicked(MyGUI::Widget* _sender) void MWAttribute::updateWidgets() { - if (attributeNameWidget && manager) + if (mAttributeNameWidget && mManager) { - if (id < 0 || id >= 8) + if (mId < 0 || mId >= 8) { - static_cast(attributeNameWidget)->setCaption(""); + static_cast(mAttributeNameWidget)->setCaption(""); } else { @@ -163,20 +167,20 @@ void MWAttribute::updateWidgets() "sAttributePersonality", "sAttributeLuck" }; - const std::string &name = manager->getGameSettingString(attributes[id], ""); - static_cast(attributeNameWidget)->setCaption(name); + const std::string &name = mManager->getGameSettingString(attributes[mId], ""); + static_cast(mAttributeNameWidget)->setCaption(name); } } - if (attributeValueWidget) + if (mAttributeValueWidget) { - AttributeValue::Type modified = value.getModified(), base = value.getBase(); - static_cast(attributeValueWidget)->setCaption(boost::lexical_cast(modified)); + AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); + static_cast(mAttributeValueWidget)->setCaption(boost::lexical_cast(modified)); if (modified > base) - attributeValueWidget->_setWidgetState("increased"); + mAttributeValueWidget->_setWidgetState("increased"); else if (modified < base) - attributeValueWidget->_setWidgetState("decreased"); + mAttributeValueWidget->_setWidgetState("decreased"); else - attributeValueWidget->_setWidgetState("normal"); + mAttributeValueWidget->_setWidgetState("normal"); } } @@ -188,14 +192,14 @@ void MWAttribute::initialiseOverride() { Base::initialiseOverride(); - assignWidget(attributeNameWidget, "StatName"); - assignWidget(attributeValueWidget, "StatValue"); - + assignWidget(mAttributeNameWidget, "StatName"); + assignWidget(mAttributeValueWidget, "StatValue"); + MyGUI::ButtonPtr button; assignWidget(button, "StatNameButton"); if (button) { - attributeNameWidget = button; + mAttributeNameWidget = button; button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); } @@ -203,7 +207,7 @@ void MWAttribute::initialiseOverride() assignWidget(button, "StatValueButton"); if (button) { - attributeValueWidget = button; + mAttributeValueWidget = button; button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); } } @@ -212,21 +216,21 @@ void MWAttribute::initialiseOverride() MWSpell::MWSpell() : mWindowManager(nullptr) - , spellNameWidget(nullptr) + , mSpellNameWidget(nullptr) { } void MWSpell::setSpellId(const std::string &spellId) { - id = spellId; + mId = spellId; updateWidgets(); } void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags) { - const ESMS::ESMStore &store = mWindowManager->getStore(); - const ESM::Spell *spell = store.spells.search(id); - MYGUI_ASSERT(spell, "spell with id '" << id << "' not found"); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Spell *spell = store.spells.search(mId); + MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); MWSpellEffectPtr effect = nullptr; std::vector::const_iterator end = spell->effects.list.end(); @@ -253,14 +257,14 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: void MWSpell::updateWidgets() { - if (spellNameWidget && mWindowManager) + if (mSpellNameWidget && mWindowManager) { - const ESMS::ESMStore &store = mWindowManager->getStore(); - const ESM::Spell *spell = store.spells.search(id); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Spell *spell = store.spells.search(mId); if (spell) - static_cast(spellNameWidget)->setCaption(spell->name); + static_cast(mSpellNameWidget)->setCaption(spell->name); else - static_cast(spellNameWidget)->setCaption(""); + static_cast(mSpellNameWidget)->setCaption(""); } } @@ -268,7 +272,7 @@ void MWSpell::initialiseOverride() { Base::initialiseOverride(); - assignWidget(spellNameWidget, "StatName"); + assignWidget(mSpellNameWidget, "StatName"); } MWSpell::~MWSpell() @@ -367,8 +371,8 @@ SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) MWSpellEffect::MWSpellEffect() : mWindowManager(nullptr) - , imageWidget(nullptr) - , textWidget(nullptr) + , mImageWidget(nullptr) + , mTextWidget(nullptr) , mRequestedWidth(0) { } @@ -384,11 +388,11 @@ void MWSpellEffect::updateWidgets() if (!mWindowManager) return; - const ESMS::ESMStore &store = mWindowManager->getStore(); + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::MagicEffect *magicEffect = store.magicEffects.search(mEffectParams.mEffectID); if (!magicEffect) return; - if (textWidget) + if (mTextWidget) { std::string pt = mWindowManager->getGameSettingString("spoint", ""); std::string pts = mWindowManager->getGameSettingString("spoints", ""); @@ -448,14 +452,14 @@ void MWSpellEffect::updateWidgets() } } - static_cast(textWidget)->setCaption(spellLine); - mRequestedWidth = textWidget->getTextSize().width + 24; + static_cast(mTextWidget)->setCaption(spellLine); + mRequestedWidth = mTextWidget->getTextSize().width + 24; } - if (imageWidget) + if (mImageWidget) { std::string path = std::string("icons\\") + magicEffect->icon; fixTexturePath(path); - imageWidget->setImageTexture(path); + mImageWidget->setImageTexture(path); } } @@ -728,49 +732,49 @@ void MWSpellEffect::initialiseOverride() { Base::initialiseOverride(); - assignWidget(textWidget, "Text"); - assignWidget(imageWidget, "Image"); + assignWidget(mTextWidget, "Text"); + assignWidget(mImageWidget, "Image"); } /* MWDynamicStat */ MWDynamicStat::MWDynamicStat() -: value(0) -, max(1) -, textWidget(nullptr) -, barWidget(nullptr) -, barTextWidget(nullptr) +: mValue(0) +, mMax(1) +, mTextWidget(nullptr) +, mBarWidget(nullptr) +, mBarTextWidget(nullptr) { } -void MWDynamicStat::setValue(int cur, int max_) +void MWDynamicStat::setValue(int cur, int max) { - value = cur; - max = max_; + mValue = cur; + mMax = max; - if (barWidget) + if (mBarWidget) { - barWidget->setProgressRange(max); - barWidget->setProgressPosition(value); + mBarWidget->setProgressRange(mMax); + mBarWidget->setProgressPosition(mValue); } - if (barTextWidget) + if (mBarTextWidget) { - if (value >= 0 && max > 0) + if (mValue >= 0 && mMax > 0) { std::stringstream out; - out << value << "/" << max; - static_cast(barTextWidget)->setCaption(out.str().c_str()); + out << mValue << "/" << mMax; + static_cast(mBarTextWidget)->setCaption(out.str().c_str()); } else - static_cast(barTextWidget)->setCaption(""); + static_cast(mBarTextWidget)->setCaption(""); } } void MWDynamicStat::setTitle(const std::string& text) { - if (textWidget) - static_cast(textWidget)->setCaption(text); + if (mTextWidget) + static_cast(mTextWidget)->setCaption(text); } MWDynamicStat::~MWDynamicStat() @@ -781,7 +785,7 @@ void MWDynamicStat::initialiseOverride() { Base::initialiseOverride(); - assignWidget(textWidget, "Text"); - assignWidget(barWidget, "Bar"); - assignWidget(barTextWidget, "BarText"); + assignWidget(mTextWidget, "Text"); + assignWidget(mBarWidget, "Bar"); + assignWidget(mBarTextWidget, "BarText"); } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 5d00baf87..9a2762369 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -10,14 +10,19 @@ #undef MYGUI_EXPORT #define MYGUI_EXPORT +namespace MWBase +{ + class WindowManager; +} + /* This file contains various custom widgets used in OpenMW. */ namespace MWGui { + /// \todo remove! using namespace MyGUI; - class WindowManager; namespace Widgets { @@ -73,7 +78,7 @@ namespace MWGui typedef std::vector SpellEffectList; - class MYGUI_EXPORT MWSkill : public Widget + class MYGUI_EXPORT MWSkill : public MyGUI::Widget { MYGUI_RTTI_DERIVED( MWSkill ); public: @@ -81,14 +86,14 @@ namespace MWGui typedef MWMechanics::Stat SkillValue; - void setWindowManager(WindowManager *m) { manager = m; } + void setWindowManager(MWBase::WindowManager *m) { mManager = m; } /// \todo remove void setSkillId(ESM::Skill::SkillEnum skillId); void setSkillNumber(int skillId); void setSkillValue(const SkillValue& value); - WindowManager *getWindowManager() const { return manager; } - ESM::Skill::SkillEnum getSkillId() const { return skillId; } - const SkillValue& getSkillValue() const { return value; } + MWBase::WindowManager *getWindowManager() const { return mManager; } + ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } + const SkillValue& getSkillValue() const { return mValue; } // Events typedef delegates::CMultiDelegate1 EventHandle_SkillVoid; @@ -109,14 +114,14 @@ namespace MWGui void updateWidgets(); - WindowManager *manager; - ESM::Skill::SkillEnum skillId; - SkillValue value; - MyGUI::WidgetPtr skillNameWidget, skillValueWidget; + MWBase::WindowManager *mManager; + ESM::Skill::SkillEnum mSkillId; + SkillValue mValue; + MyGUI::WidgetPtr mSkillNameWidget, mSkillValueWidget; }; typedef MWSkill* MWSkillPtr; - class MYGUI_EXPORT MWAttribute : public Widget + class MYGUI_EXPORT MWAttribute : public MyGUI::Widget { MYGUI_RTTI_DERIVED( MWAttribute ); public: @@ -124,13 +129,13 @@ namespace MWGui typedef MWMechanics::Stat AttributeValue; - void setWindowManager(WindowManager *m) { manager = m; } + void setWindowManager(MWBase::WindowManager *m) { mManager = m; } void setAttributeId(int attributeId); void setAttributeValue(const AttributeValue& value); - WindowManager *getWindowManager() const { return manager; } - int getAttributeId() const { return id; } - const AttributeValue& getAttributeValue() const { return value; } + MWBase::WindowManager *getWindowManager() const { return mManager; } + int getAttributeId() const { return mId; } + const AttributeValue& getAttributeValue() const { return mValue; } // Events typedef delegates::CMultiDelegate1 EventHandle_AttributeVoid; @@ -151,10 +156,10 @@ namespace MWGui void updateWidgets(); - WindowManager *manager; - int id; - AttributeValue value; - MyGUI::WidgetPtr attributeNameWidget, attributeValueWidget; + MWBase::WindowManager *mManager; + int mId; + AttributeValue mValue; + MyGUI::WidgetPtr mAttributeNameWidget, mAttributeValueWidget; }; typedef MWAttribute* MWAttributePtr; @@ -162,7 +167,7 @@ namespace MWGui * @todo remove this class and use MWEffectList instead */ class MWSpellEffect; - class MYGUI_EXPORT MWSpell : public Widget + class MYGUI_EXPORT MWSpell : public MyGUI::Widget { MYGUI_RTTI_DERIVED( MWSpell ); public: @@ -170,7 +175,7 @@ namespace MWGui typedef MWMechanics::Stat SpellValue; - void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } + void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellId(const std::string &id); /** @@ -182,7 +187,7 @@ namespace MWGui */ void createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, int flags); - const std::string &getSpellId() const { return id; } + const std::string &getSpellId() const { return mId; } protected: virtual ~MWSpell(); @@ -192,13 +197,13 @@ namespace MWGui private: void updateWidgets(); - WindowManager* mWindowManager; - std::string id; - MyGUI::TextBox* spellNameWidget; + MWBase::WindowManager* mWindowManager; + std::string mId; + MyGUI::TextBox* mSpellNameWidget; }; typedef MWSpell* MWSpellPtr; - class MYGUI_EXPORT MWEffectList : public Widget + class MYGUI_EXPORT MWEffectList : public MyGUI::Widget { MYGUI_RTTI_DERIVED( MWEffectList ); public: @@ -212,7 +217,7 @@ namespace MWGui EF_Constant = 0x02 // constant effect means that duration will not be displayed }; - void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } + void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setEffectList(const SpellEffectList& list); static SpellEffectList effectListFromESM(const ESM::EffectList* effects); @@ -234,12 +239,12 @@ namespace MWGui private: void updateWidgets(); - WindowManager* mWindowManager; + MWBase::WindowManager* mWindowManager; SpellEffectList mEffectList; }; typedef MWEffectList* MWEffectListPtr; - class MYGUI_EXPORT MWSpellEffect : public Widget + class MYGUI_EXPORT MWSpellEffect : public MyGUI::Widget { MYGUI_RTTI_DERIVED( MWSpellEffect ); public: @@ -247,7 +252,7 @@ namespace MWGui typedef ESM::ENAMstruct SpellEffectValue; - void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } + void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellEffect(const SpellEffectParams& params); std::string effectIDToString(const short effectID); @@ -262,20 +267,20 @@ namespace MWGui virtual ~MWSpellEffect(); virtual void initialiseOverride(); - + private: void updateWidgets(); - WindowManager* mWindowManager; + MWBase::WindowManager* mWindowManager; SpellEffectParams mEffectParams; - MyGUI::ImageBox* imageWidget; - MyGUI::TextBox* textWidget; + MyGUI::ImageBox* mImageWidget; + MyGUI::TextBox* mTextWidget; int mRequestedWidth; }; typedef MWSpellEffect* MWSpellEffectPtr; - class MYGUI_EXPORT MWDynamicStat : public Widget + class MYGUI_EXPORT MWDynamicStat : public MyGUI::Widget { MYGUI_RTTI_DERIVED( MWDynamicStat ); public: @@ -284,8 +289,8 @@ namespace MWGui void setValue(int value, int max); void setTitle(const std::string& text); - int getValue() const { return value; } - int getMax() const { return max; } + int getValue() const { return mValue; } + int getMax() const { return mMax; } protected: virtual ~MWDynamicStat(); @@ -294,10 +299,10 @@ namespace MWGui private: - int value, max; - MyGUI::TextBox* textWidget; - MyGUI::ProgressPtr barWidget; - MyGUI::TextBox* barTextWidget; + int mValue, mMax; + MyGUI::TextBox* mTextWidget; + MyGUI::ProgressPtr mBarWidget; + MyGUI::TextBox* mBarTextWidget; }; typedef MWDynamicStat* MWDynamicStatPtr; } diff --git a/apps/openmw/mwgui/window_base.cpp b/apps/openmw/mwgui/window_base.cpp index 433057931..dbb37efbb 100644 --- a/apps/openmw/mwgui/window_base.cpp +++ b/apps/openmw/mwgui/window_base.cpp @@ -1,11 +1,12 @@ #include "window_base.hpp" -#include "window_manager.hpp" #include +#include "../mwbase/windowmanager.hpp" + using namespace MWGui; -WindowBase::WindowBase(const std::string& parLayout, WindowManager& parWindowManager) +WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) : Layout(parLayout) , mWindowManager(parWindowManager) { diff --git a/apps/openmw/mwgui/window_base.hpp b/apps/openmw/mwgui/window_base.hpp index 9cfdbe261..74d874bb8 100644 --- a/apps/openmw/mwgui/window_base.hpp +++ b/apps/openmw/mwgui/window_base.hpp @@ -3,6 +3,11 @@ #include +namespace MWBase +{ + class WindowManager; +} + namespace MWGui { class WindowManager; @@ -10,7 +15,7 @@ namespace MWGui class WindowBase: public OEngine::GUI::Layout { public: - WindowBase(const std::string& parLayout, WindowManager& parWindowManager); + WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; @@ -25,9 +30,9 @@ namespace MWGui EventHandle_WindowBase eventDone; protected: - WindowManager& mWindowManager; + /// \todo remove + MWBase::WindowManager& mWindowManager; }; } #endif - diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp deleted file mode 100644 index 37f30c59a..000000000 --- a/apps/openmw/mwgui/window_manager.hpp +++ /dev/null @@ -1,319 +0,0 @@ -#ifndef MWGUI_WINDOWMANAGER_H -#define MWGUI_WINDOWMANAGER_H - -/** - This class owns and controls all the MW specific windows in the - GUI. It can enable/disable Gui mode, and is responsible for sending - and retrieving information from the Gui. - - MyGUI should be initialized separately before creating instances of - this class. -**/ - -#include -#include -#include - -#include "MyGUI_UString.h" - -#include -#include -#include -#include - -#include "../mwmechanics/stat.hpp" -#include "../mwworld/ptr.hpp" - -#include "mode.hpp" - -namespace MyGUI -{ - class Gui; - class Widget; -} - -namespace Compiler -{ - class Extensions; -} - -namespace MWWorld -{ - class World; -} - -namespace MWMechanics -{ - class MechanicsManager; -} - -namespace OEngine -{ - namespace GUI - { - class Layout; - } -} - -namespace MWGui -{ - class WindowBase; - class HUD; - class MapWindow; - class MainMenu; - class StatsWindow; - class InventoryWindow; - class Console; - class JournalWindow; - class CharacterCreation; - class ContainerWindow; - class DragAndDrop; - class InventoryWindow; - class ToolTips; - class ScrollWindow; - class BookWindow; - class TextInputDialog; - class InfoBoxDialog; - class DialogueWindow; - class MessageBoxManager; - class CountDialog; - class TradeWindow; - class SettingsWindow; - class ConfirmationDialog; - class AlchemyWindow; - class SpellWindow; - - struct ClassPoint - { - const char *id; - // Specialization points to match, in order: Stealth, Combat, Magic - // Note: Order is taken from http://www.uesp.net/wiki/Morrowind:Class_Quiz - unsigned int points[3]; - }; - - class WindowManager - { - public: - typedef std::pair Faction; - typedef std::vector FactionList; - typedef std::vector SkillList; - - WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath); - virtual ~WindowManager(); - - /** - * Should be called each frame to update windows/gui elements. - * This could mean updating sizes of gui elements or opening - * new dialogs. - */ - void update(); - - void pushGuiMode(GuiMode mode); - void popGuiMode(); - void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack - - GuiMode getMode() const - { - if (mGuiModes.empty()) - throw std::runtime_error ("getMode() called, but there is no active mode"); - return mGuiModes.back(); - } - - bool isGuiMode() const { return !mGuiModes.empty(); } - - void toggleVisible(GuiWindow wnd) - { - shown = (shown & wnd) ? (GuiWindow) (shown & ~wnd) : (GuiWindow) (shown | wnd); - updateVisible(); - } - - // Disallow all inventory mode windows - void disallowAll() - { - allowed = GW_None; - updateVisible(); - } - - // Allow one or more windows - void allow(GuiWindow wnd) - { - allowed = (GuiWindow)(allowed | wnd); - updateVisible(); - } - - bool isAllowed(GuiWindow wnd) const - { - return allowed & wnd; - } - - MWGui::DialogueWindow* getDialogueWindow() {return mDialogueWindow;} - MWGui::ContainerWindow* getContainerWindow() {return mContainerWindow;} - MWGui::InventoryWindow* getInventoryWindow() {return mInventoryWindow;} - MWGui::BookWindow* getBookWindow() {return mBookWindow;} - MWGui::ScrollWindow* getScrollWindow() {return mScrollWindow;} - MWGui::CountDialog* getCountDialog() {return mCountDialog;} - MWGui::ConfirmationDialog* getConfirmationDialog() {return mConfirmationDialog;} - MWGui::TradeWindow* getTradeWindow() {return mTradeWindow;} - MWGui::SpellWindow* getSpellWindow() {return mSpellWindow;} - MWGui::Console* getConsole() {return console;} - - MyGUI::Gui* getGui() const { return gui; } - - void wmUpdateFps(float fps, size_t triangleCount, size_t batchCount) - { - mFPS = fps; - mTriangleCount = triangleCount; - mBatchCount = batchCount; - } - -// MWMechanics::DynamicStat getValue(const std::string& id); - - ///< Set value for the given ID. - void setValue (const std::string& id, const MWMechanics::Stat& value); - void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setValue (const std::string& id, const std::string& value); - void setValue (const std::string& id, int value); - - void setPlayerClass (const ESM::Class &class_); ///< set current class of player - void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. - void setReputation (int reputation); ///< set the current reputation value - void setBounty (int bounty); ///< set the current bounty value - void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty - - void changeCell(MWWorld::Ptr::CellStore* cell); ///< change the active cell - void setPlayerPos(const float x, const float y); ///< set player position in map space - void setPlayerDir(const float x, const float y); ///< set player view direction in map space - - void setFocusObject(const MWWorld::Ptr& focus); - void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); - - void setMouseVisible(bool visible); - void getMousePosition(int &x, int &y); - void getMousePosition(float &x, float &y); - void setDragDrop(bool dragDrop); - bool getWorldMouseOver(); - - void toggleFogOfWar(); - void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) - bool getFullHelp() const; - - void setInteriorMapTexture(const int x, const int y); - ///< set the index of the map texture that should be used (for interiors) - - // sets the visibility of the hud health/magicka/stamina bars - void setHMSVisibility(bool visible); - // sets the visibility of the hud minimap - void setMinimapVisibility(bool visible); - void setWeaponVisibility(bool visible); - void setSpellVisibility(bool visible); - - void setSelectedSpell(const std::string& spellId, int successChancePercent); - void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); - void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); - void unsetSelectedSpell(); - void unsetSelectedWeapon(); - - template - void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr. - void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. - - void messageBox (const std::string& message, const std::vector& buttons); - int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) - - void onFrame (float frameDuration); - - std::map > getPlayerSkillValues() { return playerSkillValues; } - std::map > getPlayerAttributeValues() { return playerAttributes; } - SkillList getPlayerMinorSkills() { return playerMinorSkills; } - SkillList getPlayerMajorSkills() { return playerMajorSkills; } - - /** - * Fetches a GMST string from the store, if there is no setting with the given - * ID or it is not a string the default string is returned. - * - * @param id Identifier for the GMST setting, e.g. "aName" - * @param default Default value if the GMST setting cannot be used. - */ - const std::string &getGameSettingString(const std::string &id, const std::string &default_); - - const ESMS::ESMStore& getStore() const; - - void processChangedSettings(const Settings::CategorySettingVector& changed); - - private: - OEngine::GUI::MyGUIManager *mGuiManager; - HUD *hud; - MapWindow *map; - MainMenu *menu; - ToolTips *mToolTips; - StatsWindow *mStatsWindow; - MessageBoxManager *mMessageBoxManager; - Console *console; - JournalWindow* mJournal; - DialogueWindow *mDialogueWindow; - ContainerWindow *mContainerWindow; - DragAndDrop* mDragAndDrop; - InventoryWindow *mInventoryWindow; - ScrollWindow* mScrollWindow; - BookWindow* mBookWindow; - CountDialog* mCountDialog; - TradeWindow* mTradeWindow; - SettingsWindow* mSettingsWindow; - ConfirmationDialog* mConfirmationDialog; - AlchemyWindow* mAlchemyWindow; - SpellWindow* mSpellWindow; - - CharacterCreation* mCharGen; - - // Various stats about player as needed by window manager - ESM::Class playerClass; - std::string playerName; - std::string playerRaceId; - std::map > playerAttributes; - SkillList playerMajorSkills, playerMinorSkills; - std::map > playerSkillValues; - MWMechanics::DynamicStat playerHealth, playerMagicka, playerFatigue; - - - MyGUI::Gui *gui; // Gui - std::vector mGuiModes; - - std::vector garbageDialogs; - void cleanupGarbage(); - - GuiWindow shown; // Currently shown windows in inventory mode - - /* Currently ALLOWED windows in inventory mode. This is used at - the start of the game, when windows are enabled one by one - through script commands. You can manipulate this through using - allow() and disableAll(). - */ - GuiWindow allowed; - - void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings - - int showFPSLevel; - float mFPS; - size_t mTriangleCount; - size_t mBatchCount; - - void onDialogueWindowBye(); - - /** - * 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); - }; - - template - void WindowManager::removeDialog(T*& dialog) - { - OEngine::GUI::Layout *d = static_cast(dialog); - removeDialog(d); - dialog = 0; - } -} - -#endif diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp index ecdf311c6..4ddf49d27 100644 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ b/apps/openmw/mwgui/window_pinnable_base.cpp @@ -1,9 +1,10 @@ #include "window_pinnable_base.hpp" -#include "window_manager.hpp" + +#include "../mwbase/windowmanager.hpp" using namespace MWGui; -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, WindowManager& parWindowManager) +WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) { MyGUI::WindowPtr t = static_cast(mMainWidget); @@ -30,4 +31,3 @@ void WindowPinnableBase::onWindowButtonPressed(MyGUI::Window* sender, const std: eventDone(this); } - diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp index 86bc3b85c..250dde1f8 100644 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ b/apps/openmw/mwgui/window_pinnable_base.hpp @@ -10,13 +10,13 @@ namespace MWGui class WindowPinnableBase: public WindowBase { public: - WindowPinnableBase(const std::string& parLayout, WindowManager& parWindowManager); + WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); void setVisible(bool b); bool pinned() { return mPinned; } private: void onWindowButtonPressed(MyGUI::Window* sender, const std::string& eventName); - + protected: virtual void onPinToggled() = 0; @@ -26,4 +26,3 @@ namespace MWGui } #endif - diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp similarity index 68% rename from apps/openmw/mwgui/window_manager.cpp rename to apps/openmw/mwgui/windowmanagerimp.cpp index f62a3fa0f..183c435fd 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1,4 +1,25 @@ -#include "window_manager.hpp" +#include "windowmanagerimp.hpp" + +#include +#include + +#include "MyGUI_UString.h" + +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/inputmanager.hpp" + +#include "../mwworld/ptr.hpp" +#include "../mwworld/cellstore.hpp" + +#include "console.hpp" +#include "journalwindow.hpp" +#include "charactercreation.hpp" #include "text_input.hpp" #include "review.hpp" #include "dialogue.hpp" @@ -21,33 +42,18 @@ #include "alchemywindow.hpp" #include "spellwindow.hpp" -#include "../mwmechanics/mechanicsmanager.hpp" -#include "../mwinput/inputmanager.hpp" - -#include "../mwbase/environment.hpp" - -#include "console.hpp" -#include "journalwindow.hpp" -#include "charactercreation.hpp" - -#include - -#include -#include -#include - using namespace MWGui; WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath) + const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, bool consoleOnlyScripts) : mGuiManager(NULL) - , hud(NULL) - , map(NULL) - , menu(NULL) + , mHud(NULL) + , mMap(NULL) + , mMenu(NULL) , mStatsWindow(NULL) , mToolTips(NULL) , mMessageBoxManager(NULL) - , console(NULL) + , mConsole(NULL) , mJournal(NULL) , mDialogueWindow(NULL) , mBookWindow(NULL) @@ -59,21 +65,21 @@ WindowManager::WindowManager( , mAlchemyWindow(NULL) , mSpellWindow(NULL) , mCharGen(NULL) - , playerClass() - , playerName() - , playerRaceId() - , playerAttributes() - , playerMajorSkills() - , playerMinorSkills() - , playerSkillValues() - , playerHealth() - , playerMagicka() - , playerFatigue() - , gui(NULL) - , garbageDialogs() - , shown(GW_ALL) - , allowed(newGame ? GW_None : GW_ALL) - , showFPSLevel(fpsLevel) + , mPlayerClass() + , mPlayerName() + , mPlayerRaceId() + , mPlayerAttributes() + , mPlayerMajorSkills() + , mPlayerMinorSkills() + , mPlayerSkillValues() + , mPlayerHealth() + , mPlayerMagicka() + , mPlayerFatigue() + , mGui(NULL) + , mGarbageDialogs() + , mShown(GW_ALL) + , mAllowed(newGame ? GW_None : GW_ALL) + , mShowFPSLevel(fpsLevel) , mFPS(0.0f) , mTriangleCount(0) , mBatchCount(0) @@ -81,8 +87,8 @@ WindowManager::WindowManager( // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); - gui = mGuiManager->getGui(); - + mGui = mGuiManager->getGui(); + //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); @@ -96,11 +102,11 @@ WindowManager::WindowManager( MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); // Get size info from the Gui object - assert(gui); + assert(mGui); int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; - MyGUI::Widget* dragAndDropWidget = gui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); + MyGUI::Widget* dragAndDropWidget = mGui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); dragAndDropWidget->setVisible(false); mDragAndDrop = new DragAndDrop(); @@ -108,17 +114,17 @@ WindowManager::WindowManager( mDragAndDrop->mDraggedWidget = 0; mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - menu = new MainMenu(w,h); - map = new MapWindow(*this); + mMenu = new MainMenu(w,h); + mMap = new MapWindow(*this); mStatsWindow = new StatsWindow(*this); - console = new Console(w,h, extensions); + mConsole = new Console(w,h, consoleOnlyScripts); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); mTradeWindow = new TradeWindow(*this); mDialogueWindow = new DialogueWindow(*this); mContainerWindow = new ContainerWindow(*this,mDragAndDrop); - hud = new HUD(w,h, showFPSLevel, mDragAndDrop); + mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); mToolTips = new ToolTips(this); mScrollWindow = new ScrollWindow(*this); mBookWindow = new BookWindow(*this); @@ -129,19 +135,19 @@ WindowManager::WindowManager( mSpellWindow = new SpellWindow(*this); // The HUD is always on - hud->setVisible(true); + mHud->setVisible(true); mCharGen = new CharacterCreation(this); // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) { - playerAttributes.insert(std::make_pair(ESM::Attribute::attributeIds[i], MWMechanics::Stat())); + mPlayerAttributes.insert(std::make_pair(ESM::Attribute::attributeIds[i], MWMechanics::Stat())); } for (int i = 0; i < ESM::Skill::Length; ++i) { - playerSkillValues.insert(std::make_pair(ESM::Skill::skillIds[i], MWMechanics::Stat())); + mPlayerSkillValues.insert(std::make_pair(ESM::Skill::skillIds[i], MWMechanics::Stat())); } unsetSelectedSpell(); @@ -153,12 +159,11 @@ WindowManager::WindowManager( WindowManager::~WindowManager() { - delete mGuiManager; - delete console; + delete mConsole; delete mMessageBoxManager; - delete hud; - delete map; - delete menu; + delete mHud; + delete mMap; + delete mMenu; delete mStatsWindow; delete mJournal; delete mDialogueWindow; @@ -176,18 +181,20 @@ WindowManager::~WindowManager() delete mSpellWindow; cleanupGarbage(); + + delete mGuiManager; } void WindowManager::cleanupGarbage() { // Delete any dialogs which are no longer in use - if (!garbageDialogs.empty()) + if (!mGarbageDialogs.empty()) { - for (std::vector::iterator it = garbageDialogs.begin(); it != garbageDialogs.end(); ++it) + for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) { delete *it; } - garbageDialogs.clear(); + mGarbageDialogs.clear(); } } @@ -195,18 +202,18 @@ void WindowManager::update() { cleanupGarbage(); - hud->setFPS(mFPS); - hud->setTriangleCount(mTriangleCount); - hud->setBatchCount(mBatchCount); + mHud->setFPS(mFPS); + mHud->setTriangleCount(mTriangleCount); + mHud->setBatchCount(mBatchCount); } void WindowManager::updateVisible() { // Start out by hiding everything except the HUD - map->setVisible(false); - menu->setVisible(false); + mMap->setVisible(false); + mMenu->setVisible(false); mStatsWindow->setVisible(false); - console->disable(); + mConsole->disable(); mJournal->setVisible(false); mDialogueWindow->setVisible(false); mContainerWindow->setVisible(false); @@ -228,10 +235,10 @@ void WindowManager::updateVisible() else mToolTips->enterGuiMode(); - setMinimapVisibility((allowed & GW_Map) && !map->pinned()); - setWeaponVisibility((allowed & GW_Inventory) && !mInventoryWindow->pinned()); - setSpellVisibility((allowed & GW_Magic) && !mSpellWindow->pinned()); - setHMSVisibility((allowed & GW_Stats) && !mStatsWindow->pinned()); + setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); + setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); + setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); + setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); // If in game mode, don't show anything. if (gameMode) @@ -241,13 +248,13 @@ void WindowManager::updateVisible() switch(mode) { case GM_MainMenu: - menu->setVisible(true); + mMenu->setVisible(true); break; case GM_Settings: mSettingsWindow->setVisible(true); break; case GM_Console: - console->enable(); + mConsole->enable(); break; case GM_Scroll: mScrollWindow->setVisible(true); @@ -274,13 +281,13 @@ void WindowManager::updateVisible() // This is controlled both by what windows the // user has opened/closed (the 'shown' variable) and by what // windows we are allowed to show (the 'allowed' var.) - int eff = shown & allowed; + int eff = mShown & mAllowed; // Show the windows we want - map -> setVisible(eff & GW_Map); - mStatsWindow -> setVisible(eff & GW_Stats); + mMap ->setVisible(eff & GW_Map); + mStatsWindow ->setVisible(eff & GW_Stats); mInventoryWindow->setVisible(eff & GW_Inventory); - mSpellWindow->setVisible(eff & GW_Magic); + mSpellWindow ->setVisible(eff & GW_Magic); break; } case GM_Container: @@ -331,37 +338,39 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) +void WindowManager::setValue (int parSkill, const MWMechanics::Stat& value) { - mStatsWindow->setValue(parSkill, value); - mCharGen->setValue(parSkill, value); - playerSkillValues[parSkill] = value; + /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we + /// allow custom skills. + mStatsWindow->setValue(static_cast (parSkill), value); + mCharGen->setValue(static_cast (parSkill), value); + mPlayerSkillValues[parSkill] = value; } void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { mStatsWindow->setValue (id, value); - hud->setValue (id, value); + mHud->setValue (id, value); mCharGen->setValue(id, value); if (id == "HBar") { - playerHealth = value; + mPlayerHealth = value; mCharGen->setPlayerHealth (value); } else if (id == "MBar") { - playerMagicka = value; + mPlayerMagicka = value; mCharGen->setPlayerMagicka (value); } else if (id == "FBar") { - playerFatigue = value; + mPlayerFatigue = value; mCharGen->setPlayerFatigue (value); } } @@ -370,11 +379,11 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicS MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) { if(id == "HBar") - return playerHealth; + return layerHealth; else if (id == "MBar") - return playerMagicka; + return mPlayerMagicka; else if (id == "FBar") - return playerFatigue; + return mPlayerFatigue; } #endif @@ -382,9 +391,9 @@ void WindowManager::setValue (const std::string& id, const std::string& value) { mStatsWindow->setValue (id, value); if (id=="name") - playerName = value; + mPlayerName = value; else if (id=="race") - playerRaceId = value; + mPlayerRaceId = value; } void WindowManager::setValue (const std::string& id, int value) @@ -394,16 +403,16 @@ void WindowManager::setValue (const std::string& id, int value) void WindowManager::setPlayerClass (const ESM::Class &class_) { - playerClass = class_; - mStatsWindow->setValue("class", playerClass.name); + mPlayerClass = class_; + mStatsWindow->setValue("class", mPlayerClass.name); } void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) { mStatsWindow->configureSkills (major, minor); mCharGen->configureSkills(major, minor); - playerMajorSkills = major; - playerMinorSkills = minor; + mPlayerMajorSkills = major; + mPlayerMinorSkills = minor; } void WindowManager::setReputation (int reputation) @@ -423,11 +432,10 @@ void WindowManager::updateSkillArea() void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) { - assert(dialog); if (!dialog) return; dialog->setVisible(false); - garbageDialogs.push_back(dialog); + mGarbageDialogs.push_back(dialog); } void WindowManager::messageBox (const std::string& message, const std::vector& buttons) @@ -482,17 +490,12 @@ void WindowManager::onFrame (float frameDuration) mStatsWindow->onFrame(); - hud->onFrame(frameDuration); + mHud->onFrame(frameDuration); mDialogueWindow->checkReferenceAvailable(); mTradeWindow->checkReferenceAvailable(); mContainerWindow->checkReferenceAvailable(); - console->checkReferenceAvailable(); -} - -const ESMS::ESMStore& WindowManager::getStore() const -{ - return MWBase::Environment::get().getWorld()->getStore(); + mConsole->checkReferenceAvailable(); } void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) @@ -511,56 +514,56 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) name = getGameSettingString("sDefaultCellname", "Wilderness"); } - map->setCellName( name ); - hud->setCellName( name ); + mMap->setCellName( name ); + mHud->setCellName( name ); - map->setCellPrefix("Cell"); - hud->setCellPrefix("Cell"); - map->setActiveCell( cell->cell->data.gridX, cell->cell->data.gridY ); - hud->setActiveCell( cell->cell->data.gridX, cell->cell->data.gridY ); + mMap->setCellPrefix("Cell"); + mHud->setCellPrefix("Cell"); + mMap->setActiveCell( cell->cell->data.gridX, cell->cell->data.gridY ); + mHud->setActiveCell( cell->cell->data.gridX, cell->cell->data.gridY ); } else { - map->setCellName( cell->cell->name ); - hud->setCellName( cell->cell->name ); - map->setCellPrefix( cell->cell->name ); - hud->setCellPrefix( cell->cell->name ); + mMap->setCellName( cell->cell->name ); + mHud->setCellName( cell->cell->name ); + mMap->setCellPrefix( cell->cell->name ); + mHud->setCellPrefix( cell->cell->name ); } } void WindowManager::setInteriorMapTexture(const int x, const int y) { - map->setActiveCell(x,y, true); - hud->setActiveCell(x,y, true); + mMap->setActiveCell(x,y, true); + mHud->setActiveCell(x,y, true); } void WindowManager::setPlayerPos(const float x, const float y) { - map->setPlayerPos(x,y); - hud->setPlayerPos(x,y); + mMap->setPlayerPos(x,y); + mHud->setPlayerPos(x,y); } void WindowManager::setPlayerDir(const float x, const float y) { - map->setPlayerDir(x,y); - hud->setPlayerDir(x,y); + mMap->setPlayerDir(x,y); + mHud->setPlayerDir(x,y); } void WindowManager::setHMSVisibility(bool visible) { - hud->setBottomLeftVisibility(visible, hud->weapBox->getVisible(), hud->spellBox->getVisible()); + mHud->setBottomLeftVisibility(visible, mHud->mWeapBox->getVisible(), mHud->mSpellBox->getVisible()); } void WindowManager::setMinimapVisibility(bool visible) { - hud->setBottomRightVisibility(hud->effectBox->getVisible(), visible); + mHud->setBottomRightVisibility(mHud->mEffectBox->getVisible(), visible); } void WindowManager::toggleFogOfWar() { - map->toggleFogOfWar(); - hud->toggleFogOfWar(); + mMap->toggleFogOfWar(); + mHud->toggleFogOfWar(); } void WindowManager::setFocusObject(const MWWorld::Ptr& focus) @@ -585,13 +588,13 @@ bool WindowManager::getFullHelp() const void WindowManager::setWeaponVisibility(bool visible) { - hud->setBottomLeftVisibility(hud->health->getVisible(), visible, hud->spellBox->getVisible()); + mHud->setBottomLeftVisibility(mHud->health->getVisible(), visible, mHud->mSpellBox->getVisible()); } void WindowManager::setSpellVisibility(bool visible) { - hud->setBottomLeftVisibility(hud->health->getVisible(), hud->weapBox->getVisible(), visible); - hud->setBottomRightVisibility(visible, hud->minimapBox->getVisible()); + mHud->setBottomLeftVisibility(mHud->health->getVisible(), mHud->mWeapBox->getVisible(), visible); + mHud->setBottomRightVisibility(visible, mHud->mMinimapBox->getVisible()); } void WindowManager::setMouseVisible(bool visible) @@ -616,7 +619,7 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { - hud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); + mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); bool changeRes = false; @@ -635,16 +638,20 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector { int x = Settings::Manager::getInt("resolution x", "Video"); int y = Settings::Manager::getInt("resolution y", "Video"); - hud->onResChange(x, y); - console->onResChange(x, y); + mHud->onResChange(x, y); + mConsole->onResChange(x, y); + mMenu->onResChange(x, y); mSettingsWindow->center(); + mAlchemyWindow->center(); + mScrollWindow->center(); + mBookWindow->center(); mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); } } void WindowManager::pushGuiMode(GuiMode mode) { - if (mode==GM_Inventory && allowed==GW_None) + if (mode==GM_Inventory && mAllowed==GW_None) return; mGuiModes.push_back(mode); @@ -685,32 +692,32 @@ void WindowManager::removeGuiMode(GuiMode mode) void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) { - hud->setSelectedSpell(spellId, successChancePercent); + mHud->setSelectedSpell(spellId, successChancePercent); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().spells.find(spellId); mSpellWindow->setTitle(spell->name); } void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) { - hud->setSelectedEnchantItem(item, chargePercent); + mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); } void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) { - hud->setSelectedWeapon(item, durabilityPercent); + mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); } void WindowManager::unsetSelectedSpell() { - hud->unsetSelectedSpell(); + mHud->unsetSelectedSpell(); mSpellWindow->setTitle("#{sNone}"); } void WindowManager::unsetSelectedWeapon() { - hud->unsetSelectedWeapon(); + mHud->unsetSelectedWeapon(); mInventoryWindow->setTitle("#{sSkillHandtohand}"); } @@ -733,5 +740,86 @@ void WindowManager::getMousePosition(float &x, float &y) bool WindowManager::getWorldMouseOver() { - return hud->getWorldMouseOver(); + return mHud->getWorldMouseOver(); +} + +void WindowManager::executeInConsole (const std::string& path) +{ + mConsole->executeFile (path); +} + +void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) +{ + mFPS = fps; + mTriangleCount = triangleCount; + mBatchCount = batchCount; +} + +MyGUI::Gui* WindowManager::getGui() const { return mGui; } + +MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } +MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } +MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } +MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } +MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } +MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } +MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } +MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } +MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } +MWGui::Console* WindowManager::getConsole() { return mConsole; } + +bool WindowManager::isAllowed (GuiWindow wnd) const +{ + return mAllowed & wnd; +} + +void WindowManager::allow (GuiWindow wnd) +{ + mAllowed = (GuiWindow)(mAllowed | wnd); + updateVisible(); +} + +void WindowManager::disallowAll() +{ + mAllowed = GW_None; + updateVisible(); +} + +void WindowManager::toggleVisible (GuiWindow wnd) +{ + mShown = (mShown & wnd) ? (GuiWindow) (mShown & ~wnd) : (GuiWindow) (mShown | wnd); + updateVisible(); +} + +bool WindowManager::isGuiMode() const +{ + return !mGuiModes.empty(); +} + +MWGui::GuiMode WindowManager::getMode() const +{ + if (mGuiModes.empty()) + throw std::runtime_error ("getMode() called, but there is no active mode"); + + return mGuiModes.back(); +} + +std::map > WindowManager::getPlayerSkillValues() +{ + return mPlayerSkillValues; +} + +std::map > WindowManager::getPlayerAttributeValues() +{ + return mPlayerAttributes; +} + +WindowManager::SkillList WindowManager::getPlayerMinorSkills() +{ + return mPlayerMinorSkills; +} + +WindowManager::SkillList WindowManager::getPlayerMajorSkills() +{ + return mPlayerMajorSkills; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp new file mode 100644 index 000000000..eaa6a1683 --- /dev/null +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -0,0 +1,254 @@ +#ifndef MWGUI_WINDOWMANAGERIMP_H +#define MWGUI_WINDOWMANAGERIMP_H + +/** + This class owns and controls all the MW specific windows in the + GUI. It can enable/disable Gui mode, and is responsible for sending + and retrieving information from the Gui. + + MyGUI should be initialized separately before creating instances of + this class. +**/ + +#include +#include + +#include + +#include "../mwbase/windowmanager.hpp" + +namespace MyGUI +{ + class Gui; + class Widget; + class UString; +} + +namespace Compiler +{ + class Extensions; +} + +namespace OEngine +{ + namespace GUI + { + class Layout; + class MyGUIManager; + } + + namespace Render + { + class OgreRenderer; + } +} + +namespace MWGui +{ + class WindowBase; + class HUD; + class MapWindow; + class MainMenu; + class StatsWindow; + class InventoryWindow; + class JournalWindow; + class CharacterCreation; + class DragAndDrop; + class ToolTips; + class TextInputDialog; + class InfoBoxDialog; + class MessageBoxManager; + class SettingsWindow; + class AlchemyWindow; + + class WindowManager : public MWBase::WindowManager + { + public: + typedef std::pair Faction; + typedef std::vector FactionList; + + WindowManager(const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *mOgre, const std::string& logpath, bool consoleOnlyScripts); + virtual ~WindowManager(); + + /** + * Should be called each frame to update windows/gui elements. + * This could mean updating sizes of gui elements or opening + * new dialogs. + */ + virtual void update(); + + virtual void pushGuiMode(GuiMode mode); + virtual void popGuiMode(); + virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack + + virtual GuiMode getMode() const; + + virtual bool isGuiMode() const; + + virtual void toggleVisible(GuiWindow wnd); + + // Disallow all inventory mode windows + virtual void disallowAll(); + + // Allow one or more windows + virtual void allow(GuiWindow wnd); + + virtual bool isAllowed(GuiWindow wnd) const; + + /// \todo investigate, if we really need to expose every single lousy UI element to the outside world + virtual MWGui::DialogueWindow* getDialogueWindow(); + virtual MWGui::ContainerWindow* getContainerWindow(); + virtual MWGui::InventoryWindow* getInventoryWindow(); + virtual MWGui::BookWindow* getBookWindow(); + virtual MWGui::ScrollWindow* getScrollWindow(); + virtual MWGui::CountDialog* getCountDialog(); + virtual MWGui::ConfirmationDialog* getConfirmationDialog(); + virtual MWGui::TradeWindow* getTradeWindow(); + virtual MWGui::SpellWindow* getSpellWindow(); + virtual MWGui::Console* getConsole(); + + virtual MyGUI::Gui* getGui() const; + + virtual void wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount); + + ///< Set value for the given ID. + virtual void setValue (const std::string& id, const MWMechanics::Stat& value); + virtual void setValue (int parSkill, const MWMechanics::Stat& value); + virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + virtual void setValue (const std::string& id, const std::string& value); + virtual void setValue (const std::string& id, int value); + + virtual void setPlayerClass (const ESM::Class &class_); ///< set current class of player + virtual void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. + virtual void setReputation (int reputation); ///< set the current reputation value + virtual void setBounty (int bounty); ///< set the current bounty value + virtual void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty + + virtual void changeCell(MWWorld::CellStore* cell); ///< change the active cell + virtual void setPlayerPos(const float x, const float y); ///< set player position in map space + virtual void setPlayerDir(const float x, const float y); ///< set player view direction in map space + + 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); + virtual bool getWorldMouseOver(); + + virtual void toggleFogOfWar(); + virtual void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) + virtual bool getFullHelp() const; + + virtual void setInteriorMapTexture(const int x, const int y); + ///< set the index of the map texture that should be used (for interiors) + + // sets the visibility of the hud health/magicka/stamina bars + virtual void setHMSVisibility(bool visible); + // sets the visibility of the hud minimap + virtual void setMinimapVisibility(bool visible); + virtual void setWeaponVisibility(bool visible); + virtual void setSpellVisibility(bool visible); + + virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); + virtual void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); + virtual void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); + virtual void unsetSelectedSpell(); + virtual void unsetSelectedWeapon(); + + virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. + + virtual void messageBox (const std::string& message, const std::vector& buttons); + virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) + + virtual void onFrame (float frameDuration); + + /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. + virtual std::map > getPlayerSkillValues(); + virtual std::map > getPlayerAttributeValues(); + virtual SkillList getPlayerMinorSkills(); + virtual SkillList getPlayerMajorSkills(); + + /** + * Fetches a GMST string from the store, if there is no setting with the given + * ID or it is not a string the default string is returned. + * + * @param id Identifier for the GMST setting, e.g. "aName" + * @param default Default value if the GMST setting cannot be used. + */ + virtual const std::string &getGameSettingString(const std::string &id, const std::string &default_); + + virtual void processChangedSettings(const Settings::CategorySettingVector& changed); + + virtual void executeInConsole (const std::string& path); + + private: + OEngine::GUI::MyGUIManager *mGuiManager; + HUD *mHud; + MapWindow *mMap; + MainMenu *mMenu; + ToolTips *mToolTips; + StatsWindow *mStatsWindow; + MessageBoxManager *mMessageBoxManager; + Console *mConsole; + JournalWindow* mJournal; + DialogueWindow *mDialogueWindow; + ContainerWindow *mContainerWindow; + DragAndDrop* mDragAndDrop; + InventoryWindow *mInventoryWindow; + ScrollWindow* mScrollWindow; + BookWindow* mBookWindow; + CountDialog* mCountDialog; + TradeWindow* mTradeWindow; + SettingsWindow* mSettingsWindow; + ConfirmationDialog* mConfirmationDialog; + AlchemyWindow* mAlchemyWindow; + SpellWindow* mSpellWindow; + + CharacterCreation* mCharGen; + + /// \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 + ESM::Class mPlayerClass; + std::string mPlayerName; + std::string mPlayerRaceId; + std::map > mPlayerAttributes; + SkillList mPlayerMajorSkills, mPlayerMinorSkills; + std::map > mPlayerSkillValues; + MWMechanics::DynamicStat mPlayerHealth, mPlayerMagicka, mPlayerFatigue; + + + MyGUI::Gui *mGui; // Gui + std::vector mGuiModes; + + std::vector mGarbageDialogs; + void cleanupGarbage(); + + GuiWindow mShown; // Currently shown windows in inventory mode + + /* Currently ALLOWED windows in inventory mode. This is used at + the start of the game, when windows are enabled one by one + through script commands. You can manipulate this through using + allow() and disableAll(). + */ + GuiWindow mAllowed; + + void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings + + int mShowFPSLevel; + float mFPS; + unsigned int mTriangleCount; + unsigned int mBatchCount; + + void onDialogueWindowBye(); + + /** + * 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); + }; +} + +#endif diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp similarity index 73% rename from apps/openmw/mwinput/inputmanager.cpp rename to apps/openmw/mwinput/inputmanagerimp.cpp index a2bafcbf7..8def5c74d 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1,26 +1,27 @@ -#include "inputmanager.hpp" +#include "inputmanagerimp.hpp" + +#include #include #include #include -#include -#include #include -#include "../mwgui/window_manager.hpp" +#include "../mwbase/windowmanager.hpp" #include #include #include +#include "mouselookevent.hpp" + #include "../engine.hpp" #include "../mwworld/player.hpp" - -#include "../mwrender/player.hpp" +#include "../mwbase/world.hpp" #include #include @@ -69,8 +70,6 @@ namespace MWInput A_ToggleWeapon, A_ToggleSpell, - A_Settings, // Temporary hotkey - A_LAST // Marker for the last item }; @@ -79,17 +78,17 @@ namespace MWInput { OEngine::Input::DispatcherPtr disp; OEngine::Render::OgreRenderer &ogre; - OEngine::Render::ExitListener exit; Mangle::Input::OISDriver input; OEngine::Input::Poller poller; - OEngine::Render::MouseLookEventPtr mouse; + MouseLookEventPtr mouse; OEngine::GUI::EventInjectorPtr guiEvents; MWWorld::Player &player; - MWGui::WindowManager &windows; + MWBase::WindowManager &windows; OMW::Engine& mEngine; bool mDragDrop; + std::map mControlSwitch; /* InputImpl Methods */ public: @@ -102,15 +101,15 @@ private: { if (windows.isGuiMode()) return; - DrawState state = player.getDrawState(); - if (state == DrawState_Weapon || state == DrawState_Nothing) + MWMechanics::DrawState_ state = player.getDrawState(); + if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing) { - player.setDrawState(DrawState_Spell); + player.setDrawState(MWMechanics::DrawState_Spell); std::cout << "Player has now readied his hands for spellcasting!\n"; } else { - player.setDrawState(DrawState_Nothing); + player.setDrawState(MWMechanics::DrawState_Nothing); std::cout << "Player does not have any kind of attack ready now.\n"; } } @@ -119,15 +118,15 @@ private: { if (windows.isGuiMode()) return; - DrawState state = player.getDrawState(); - if (state == DrawState_Spell || state == DrawState_Nothing) + MWMechanics::DrawState_ state = player.getDrawState(); + if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) { - player.setDrawState(DrawState_Weapon); + player.setDrawState(MWMechanics::DrawState_Weapon); std::cout << "Player is now drawing his weapon.\n"; } else { - player.setDrawState(DrawState_Nothing); + player.setDrawState(MWMechanics::DrawState_Nothing); std::cout << "Player does not have any kind of attack ready now.\n"; } } @@ -140,15 +139,6 @@ private: windows.messageBox ("Screenshot saved", empty); } - void showSettings() - { - if (mDragDrop) - return; - - if (!windows.isGuiMode() || windows.getMode() != MWGui::GM_Settings) - windows.pushGuiMode(MWGui::GM_Settings); - } - /* toggleInventory() is called when the user presses the button to toggle the inventory screen. */ void toggleInventory() { @@ -222,21 +212,28 @@ private: player.toggleRunning(); } + void toggleMainMenu() + { + if (windows.isGuiMode () && (windows.getMode () == MWGui::GM_MainMenu || windows.getMode () == MWGui::GM_Settings)) + windows.popGuiMode(); + else + windows.pushGuiMode (MWGui::GM_MainMenu); + } + // Exit program now button (which is disabled in GUI mode) void exitNow() { if(!windows.isGuiMode()) - exit.exitNow(); + Ogre::Root::getSingleton().queueEndRendering (); } public: InputImpl(OEngine::Render::OgreRenderer &_ogre, MWWorld::Player &_player, - MWGui::WindowManager &_windows, + MWBase::WindowManager &_windows, bool debug, OMW::Engine& engine) : ogre(_ogre), - exit(ogre.getWindow()), input(ogre.getWindow(), !debug), poller(input), player(_player), @@ -273,13 +270,10 @@ private: "Draw Weapon"); disp->funcs.bind(A_ToggleSpell,boost::bind(&InputImpl::toggleSpell,this), "Ready hands"); - disp->funcs.bind(A_Settings, boost::bind(&InputImpl::showSettings, this), - "Show settings window"); - // Add the exit listener - ogre.getRoot()->addFrameListener(&exit); + disp->funcs.bind(A_GameMenu, boost::bind(&InputImpl::toggleMainMenu, this), + "Toggle main menu"); - // Set up the mouse handler and tell it about the player camera - mouse = MouseLookEventPtr(new MouseLookEvent(player.getRenderer()->getCamera())); + mouse = MouseLookEventPtr(new MouseLookEvent()); // This event handler pumps events into MyGUI guiEvents = EventInjectorPtr(new EventInjector(windows.getGui())); @@ -296,6 +290,14 @@ private: lst->add(guiEvents,Event::EV_ALL); } + mControlSwitch["playercontrols"] = true; + mControlSwitch["playerfighting"] = true; + mControlSwitch["playerjumping"] = true; + mControlSwitch["playerlooking"] = true; + mControlSwitch["playermagic"] = true; + mControlSwitch["playerviewswitch"] = true; + mControlSwitch["vanitymode"] = true; + changeInputMode(false); /********************************** @@ -309,7 +311,7 @@ private: // NOTE: These keys do not require constant polling - use in conjuction with variables in loops. disp->bind(A_Quit, KC_Q); - disp->bind(A_Quit, KC_ESCAPE); + disp->bind(A_GameMenu, KC_ESCAPE); disp->bind(A_Screenshot, KC_SYSRQ); disp->bind(A_Inventory, KC_I); disp->bind(A_Console, KC_F1); @@ -320,7 +322,6 @@ private: disp->bind(A_ToggleWalk, KC_C); disp->bind(A_ToggleWeapon,KC_F); disp->bind(A_ToggleSpell,KC_R); - disp->bind(A_Settings, KC_F2); // Key bindings for polled keys // NOTE: These keys are constantly being polled. Only add keys that must be checked each frame. @@ -336,7 +337,7 @@ private: poller.bind(A_MoveRight, KC_D); poller.bind(A_MoveForward, KC_W); poller.bind(A_MoveBackward, KC_S); - + poller.bind(A_Jump, KC_E); poller.bind(A_Crouch, KC_LCONTROL); } @@ -366,38 +367,40 @@ private: // Configure player movement according to keyboard input. Actual movement will // be done in the physics system. - if (poller.isDown(A_MoveLeft)) - { - player.setAutoMove (false); - player.setLeftRight (1); - } - else if (poller.isDown(A_MoveRight)) - { - player.setAutoMove (false); - player.setLeftRight (-1); - } - else - player.setLeftRight (0); + if (mControlSwitch["playercontrols"]) { + if (poller.isDown(A_MoveLeft)) + { + player.setAutoMove (false); + player.setLeftRight (1); + } + else if (poller.isDown(A_MoveRight)) + { + player.setAutoMove (false); + player.setLeftRight (-1); + } + else + player.setLeftRight (0); - if (poller.isDown(A_MoveForward)) - { - player.setAutoMove (false); - player.setForwardBackward (1); - } - else if (poller.isDown(A_MoveBackward)) - { - player.setAutoMove (false); - player.setForwardBackward (-1); - } - else - player.setForwardBackward (0); + if (poller.isDown(A_MoveForward)) + { + player.setAutoMove (false); + player.setForwardBackward (1); + } + else if (poller.isDown(A_MoveBackward)) + { + player.setAutoMove (false); + player.setForwardBackward (-1); + } + else + player.setForwardBackward (0); - if (poller.isDown(A_Jump)) - player.setUpDown (1); - else if (poller.isDown(A_Crouch)) - player.setUpDown (-1); - else - player.setUpDown (0); + if (poller.isDown(A_Jump) && mControlSwitch["playerjumping"]) + player.setUpDown (1); + else if (poller.isDown(A_Crouch)) + player.setUpDown (-1); + else + player.setUpDown (0); + } } // Switch between gui modes. Besides controlling the Gui windows @@ -408,27 +411,53 @@ private: if(guiMode) { // Disable mouse look - mouse->setCamera(NULL); + mouse->disable(); // Enable GUI events guiEvents->enabled = true; } else { - // Start mouse-looking again. TODO: This should also allow - // for other ways to disable mouselook, like paralyzation. - mouse->setCamera(player.getRenderer()->getCamera()); + // Start mouse-looking again if allowed. + if (mControlSwitch["playerlooking"]) { + mouse->enable(); + } // Disable GUI events guiEvents->enabled = false; } } + + void toggleControlSwitch(std::string sw, bool value) + { + if (mControlSwitch[sw] == value) { + return; + } + /// \note 7 switches at all, if-else is relevant + if (sw == "playercontrols" && !value) { + player.setLeftRight(0); + player.setForwardBackward(0); + player.setAutoMove(false); + player.setUpDown(0); + } else if (sw == "playerjumping" && !value) { + /// \fixme maybe crouching at this time + player.setUpDown(0); + } else if (sw == "playerlooking") { + if (value) { + mouse->enable(); + } else { + mouse->disable(); + } + } + mControlSwitch[sw] = value; + } + }; /***CONSTRUCTOR***/ MWInputManager::MWInputManager(OEngine::Render::OgreRenderer &ogre, MWWorld::Player &player, - MWGui::WindowManager &windows, + MWBase::WindowManager &windows, bool debug, OMW::Engine& engine) { @@ -471,4 +500,9 @@ private: if (changeRes) impl->adjustMouseRegion(Settings::Manager::getInt("resolution x", "Video"), Settings::Manager::getInt("resolution y", "Video")); } + + void MWInputManager::toggleControlSwitch (const std::string& sw, bool value) + { + impl->toggleControlSwitch(sw, value); + } } diff --git a/apps/openmw/mwinput/inputmanager.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp similarity index 57% rename from apps/openmw/mwinput/inputmanager.hpp rename to apps/openmw/mwinput/inputmanagerimp.hpp index 4ef3df137..5092198da 100644 --- a/apps/openmw/mwinput/inputmanager.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -1,10 +1,12 @@ -#ifndef _MWINPUT_MWINPUTMANAGER_H -#define _MWINPUT_MWINPUTMANAGER_H +#ifndef _MWINPUT_MWINPUTMANAGERIMP_H +#define _MWINPUT_MWINPUTMANAGERIMP_H #include "../mwgui/mode.hpp" #include +#include "../mwbase/inputmanager.hpp" + namespace OEngine { namespace Render @@ -18,7 +20,7 @@ namespace MWWorld class Player; } -namespace MWGui +namespace MWBase { class WindowManager; } @@ -38,25 +40,27 @@ namespace MWInput This class is just an interface. All the messy details are in inputmanager.cpp. */ - struct MWInputManager + struct MWInputManager : public MWBase::InputManager { InputImpl *impl; public: MWInputManager(OEngine::Render::OgreRenderer &_ogre, MWWorld::Player&_player, - MWGui::WindowManager &_windows, + MWBase::WindowManager &_windows, bool debug, OMW::Engine& engine); - ~MWInputManager(); + virtual ~MWInputManager(); - void update(); + virtual void update(); - void changeInputMode(bool guiMode); + virtual void changeInputMode(bool guiMode); - void processChangedSettings(const Settings::CategorySettingVector& changed); + virtual void processChangedSettings(const Settings::CategorySettingVector& changed); - void setDragDrop(bool dragDrop); + virtual void setDragDrop(bool dragDrop); + + virtual void toggleControlSwitch (const std::string& sw, bool value); }; } #endif diff --git a/apps/openmw/mwinput/mouselookevent.cpp b/apps/openmw/mwinput/mouselookevent.cpp new file mode 100644 index 000000000..f318ce666 --- /dev/null +++ b/apps/openmw/mwinput/mouselookevent.cpp @@ -0,0 +1,28 @@ +#include "mouselookevent.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" + +#include +#include +#include + +using namespace OIS; +using namespace MWInput; + +void MouseLookEvent::event(Type type, int index, const void *p) +{ + if (type != EV_MouseMove || mDisabled) { + return; + } + + MouseEvent *arg = (MouseEvent*)(p); + + float x = arg->state.X.rel * sensX; + float y = arg->state.Y.rel * sensY; + + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); +} diff --git a/apps/openmw/mwinput/mouselookevent.hpp b/apps/openmw/mwinput/mouselookevent.hpp new file mode 100644 index 000000000..af996643f --- /dev/null +++ b/apps/openmw/mwinput/mouselookevent.hpp @@ -0,0 +1,57 @@ +#ifndef _MWINPUT_MOUSELOOKEVENT_H +#define _MWINPUT_MOUSELOOKEVENT_H + +/* + A mouse-look class for Ogre. Accepts input events from Mangle::Input + and translates them. + + You can adjust the mouse sensibility and switch to a different + camera. The mouselook class also has an optional wrap protection + that keeps the camera from flipping upside down. + + You can disable the mouse looker at any time by calling + setCamera(NULL), and reenable it by setting the camera back. + + NOTE: The current implementation will ONLY work for native OIS + events. + */ + +#include + +namespace MWInput +{ + class MouseLookEvent : public Mangle::Input::Event + { + float sensX, sensY; // Mouse sensibility + bool flipProt; // Flip protection + bool mDisabled; + + public: + MouseLookEvent(float sX = 0.2, float sY = 0.2, bool prot=true) + : sensX(sX), sensY(sY), flipProt(prot) + {} + + void setSens(float sX, float sY) { + sensX = sX; + sensY = sY; + } + + void setProt(bool p) { + flipProt = p; + } + + void disable() { + mDisabled = true; + } + + void enable() { + mDisabled = false; + } + + void event(Type type, int index, const void *p); + }; + + typedef boost::shared_ptr MouseLookEventPtr; +} + +#endif diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index ced2a5c3f..94b98d3be 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -3,9 +3,13 @@ #include -#include "../mwbase/environment.hpp" +#include +#include -#include "../mwworld/world.hpp" +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" namespace MWMechanics { @@ -42,14 +46,13 @@ namespace MWMechanics for (TIterator iter (begin()); iter!=end(); ++iter) { - const ESM::Spell& spell = - *MWBase::Environment::get().getWorld()->getStore().spells.find (iter->first); + const ESM::EffectList& effects = getEffectList (iter->first); const MWWorld::TimeStamp& start = iter->second.first; float magnitude = iter->second.second; - for (std::vector::const_iterator iter (spell.effects.list.begin()); - iter!=spell.effects.list.end(); ++iter) + for (std::vector::const_iterator iter (effects.list.begin()); + iter!=effects.list.end(); ++iter) { if (iter->duration) { @@ -70,18 +73,31 @@ namespace MWMechanics } } + const ESM::EffectList& ActiveSpells::getEffectList (const std::string& id) const + { + if (const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().spells.search (id)) + return spell->effects; + + if (const ESM::Potion *potion = + MWBase::Environment::get().getWorld()->getStore().potions.search (id)) + return potion->effects; + + throw std::runtime_error ("ID " + id + " can not produce lasting effects"); + } + ActiveSpells::ActiveSpells() : mSpellsChanged (false), mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp()) {} - void ActiveSpells::addSpell (const std::string& id) + bool ActiveSpells::addSpell (const std::string& id) { - const ESM::Spell& spell = *MWBase::Environment::get().getWorld()->getStore().spells.find (id); + const ESM::EffectList& effects = getEffectList (id); bool found = false; - for (std::vector::const_iterator iter (spell.effects.list.begin()); - iter!=spell.effects.list.end(); ++iter) + for (std::vector::const_iterator iter (effects.list.begin()); + iter!=effects.list.end(); ++iter) { if (iter->duration) { @@ -91,7 +107,7 @@ namespace MWMechanics } if (!found) - return; + return false; TContainer::iterator iter = mSpells.find (id); @@ -104,6 +120,8 @@ namespace MWMechanics iter->second = std::make_pair (MWBase::Environment::get().getWorld()->getTimeStamp(), random); mSpellsChanged = true; + + return true; } void ActiveSpells::removeSpell (const std::string& id) @@ -137,13 +155,12 @@ namespace MWMechanics double ActiveSpells::timeToExpire (const TIterator& iterator) const { - const ESM::Spell& spell = - *MWBase::Environment::get().getWorld()->getStore().spells.find (iterator->first); + const ESM::EffectList& effects = getEffectList (iterator->first); int duration = 0; - for (std::vector::const_iterator iter (spell.effects.list.begin()); - iter!=spell.effects.list.end(); ++iter) + for (std::vector::const_iterator iter (effects.list.begin()); + iter!=effects.list.end(); ++iter) { if (iter->duration>duration) duration = iter->duration; diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index 179321c58..2226cea84 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -12,11 +12,15 @@ namespace ESM { struct Spell; + struct EffectList; } namespace MWMechanics { /// \brief Lasting spell effects + /// + /// \note The name of this class is slightly misleading, since it also handels lasting potion + /// effects. class ActiveSpells { public: @@ -33,13 +37,17 @@ namespace MWMechanics void update() const; + const ESM::EffectList& getEffectList (const std::string& id) const; + public: ActiveSpells(); - void addSpell (const std::string& id); + bool addSpell (const std::string& id); ///< Overwrites an existing spell with the same ID. If the spell does not have any /// non-instant effects, it is ignored. + /// + /// \return Has the spell been added? void removeSpell (const std::string& id); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8f8fd6871..e1c5f855f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -3,6 +3,8 @@ #include +#include + #include #include "../mwworld/class.hpp" @@ -16,22 +18,8 @@ namespace MWMechanics { // magic effects adjustMagicEffects (ptr); - - CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); - - // calculate dynamic stats - int strength = creatureStats.mAttributes[0].getBase(); - int intelligence = creatureStats.mAttributes[1].getBase(); - int willpower = creatureStats.mAttributes[2].getBase(); - int agility = creatureStats.mAttributes[3].getBase(); - int endurance = creatureStats.mAttributes[5].getBase(); - - double magickaFactor = creatureStats.mMagicEffects.get (EffectKey (84)).mMagnitude*0.1 + 0.5; - - creatureStats.mDynamic[0].setBase (static_cast (0.5 * (strength + endurance))); - creatureStats.mDynamic[1].setBase (static_cast (intelligence + - magickaFactor * intelligence)); - creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance); + calculateCreatureStatModifiers (ptr); + calculateDynamicStats (ptr); } void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) @@ -45,7 +33,7 @@ namespace MWMechanics { CreatureStats& creatureStats = MWWorld::Class::get (creature).getCreatureStats (creature); - MagicEffects now = creatureStats.mSpells.getMagicEffects(); + MagicEffects now = creatureStats.getSpells().getMagicEffects(); if (creature.getTypeName()==typeid (ESM::NPC).name()) { @@ -53,15 +41,64 @@ namespace MWMechanics now += store.getMagicEffects(); } - now += creatureStats.mActiveSpells.getMagicEffects(); + now += creatureStats.getActiveSpells().getMagicEffects(); - MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now); + MagicEffects diff = MagicEffects::diff (creatureStats.getMagicEffects(), now); - creatureStats.mMagicEffects = now; + creatureStats.setMagicEffects(now); // TODO apply diff to other stats } + void Actors::calculateDynamicStats (const MWWorld::Ptr& ptr) + { + CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); + + int strength = creatureStats.getAttribute(0).getBase(); + int intelligence = creatureStats.getAttribute(1).getBase(); + int willpower = creatureStats.getAttribute(2).getBase(); + int agility = creatureStats.getAttribute(3).getBase(); + int endurance = creatureStats.getAttribute(5).getBase(); + + double magickaFactor = + creatureStats.getMagicEffects().get (EffectKey (84)).mMagnitude * 0.1 + 0.5; + + creatureStats.getHealth().setBase( + static_cast (0.5 * (strength + endurance))); + + creatureStats.getMagicka().setBase( + static_cast (intelligence + magickaFactor * intelligence)); + + creatureStats.getFatigue().setBase(strength+willpower+agility+endurance); + } + + void Actors::calculateCreatureStatModifiers (const MWWorld::Ptr& ptr) + { + CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); + + // attributes + for (int i=0; i<5; ++i) + { + int modifier = + creatureStats.getMagicEffects().get (EffectKey (79, i)).mMagnitude; + + modifier -= creatureStats.getMagicEffects().get (EffectKey (17, i)).mMagnitude; + + creatureStats.getAttribute(i).setModifier (modifier); + } + + // dynamic stats + MagicEffects effects = creatureStats.getMagicEffects(); + creatureStats.getHealth().setModifier( + effects.get(EffectKey(80)).mMagnitude - effects.get(EffectKey(18)).mMagnitude); + + creatureStats.getMagicka().setModifier( + effects.get(EffectKey(81)).mMagnitude - effects.get(EffectKey(19)).mMagnitude); + + creatureStats.getFatigue().setModifier( + effects.get(EffectKey(82)).mMagnitude - effects.get(EffectKey(20)).mMagnitude); + } + Actors::Actors() : mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) @@ -97,15 +134,16 @@ namespace MWMechanics if (mDuration>=0.25) { + float totalDuration = mDuration; + mDuration = 0; + for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); ++iter) { - updateActor (*iter, mDuration); + updateActor (*iter, totalDuration); if (iter->getTypeName()==typeid (ESM::NPC).name()) - updateNpc (*iter, mDuration, paused); + updateNpc (*iter, totalDuration, paused); } - - mDuration = 0; } for (std::set::iterator iter (mActors.begin()); iter!=mActors.end(); diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 1be29463f..d5dcef487 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -5,13 +5,17 @@ #include #include -#include "../mwworld/ptr.hpp" - namespace Ogre { class Vector3; } +namespace MWWorld +{ + class Ptr; + class CellStore; +} + namespace MWMechanics { class Actors @@ -23,6 +27,10 @@ namespace MWMechanics void adjustMagicEffects (const MWWorld::Ptr& creature); + void calculateDynamicStats (const MWWorld::Ptr& ptr); + + void calculateCreatureStatModifiers (const MWWorld::Ptr& ptr); + public: Actors(); @@ -35,7 +43,7 @@ namespace MWMechanics /// /// \note Ignored, if \a ptr is not a registered actor. - void dropActors (const MWWorld::Ptr::CellStore *cellStore); + void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. void update (std::vector >& movement, diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp new file mode 100644 index 000000000..38d2442fa --- /dev/null +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -0,0 +1,48 @@ +#include "creaturestats.hpp" + +namespace MWMechanics +{ + CreatureStats::CreatureStats() + {} + + // Can't use all benefits of members initialization because of + // lack of copy constructors + CreatureStats::CreatureStats(const CreatureStats &orig) + : mLevel(orig.mLevel), mHello(orig.mHello), mFight(orig.mFight), + mFlee(orig.mFlee), mAlarm(orig.mAlarm) + { + for (int i = 0; i < 8; ++i) { + mAttributes[i] = orig.mAttributes[i]; + } + for (int i = 0; i < 3; ++i) { + mDynamic[i] = orig.mDynamic[i]; + } + mSpells = orig.mSpells; + mActiveSpells = orig.mActiveSpells; + mMagicEffects = orig.mMagicEffects; + } + + CreatureStats::~CreatureStats() + {} + + const CreatureStats & + CreatureStats::operator=(const CreatureStats &orig) + { + for (int i = 0; i < 8; ++i) { + mAttributes[i] = orig.mAttributes[i]; + } + for (int i = 0; i < 3; ++i) { + mDynamic[i] = orig.mDynamic[i]; + } + mLevel = orig.mLevel; + mSpells = orig.mSpells; + mActiveSpells = orig.mActiveSpells; + mMagicEffects = orig.mMagicEffects; + mHello = orig.mHello; + mFight = orig.mFight; + mFlee = orig.mFlee; + mAlarm = orig.mAlarm; + + return *this; + } +} diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 8d40e1942..9d69c868f 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "stat.hpp" #include "magiceffects.hpp" @@ -11,7 +12,10 @@ namespace MWMechanics { - struct CreatureStats + /// \brief Common creature stats + /// + /// + class CreatureStats { Stat mAttributes[8]; DynamicStat mDynamic[3]; // health, magicka, fatigue @@ -23,7 +27,258 @@ namespace MWMechanics int mFight; int mFlee; int mAlarm; + + public: + CreatureStats(); + CreatureStats(const CreatureStats &); + virtual ~CreatureStats(); + + const CreatureStats & operator=(const CreatureStats &); + + const Stat & getAttribute(int index) const; + + const DynamicStat & getHealth() const; + + const DynamicStat & getMagicka() const; + + const DynamicStat & getFatigue() const; + + const Spells & getSpells() const; + + const ActiveSpells & getActiveSpells() const; + + const MagicEffects & getMagicEffects() const; + + int getLevel() const; + + int getHello() const; + + int getFight() const; + + int getFlee() const; + + int getAlarm() const; + + + Stat & getAttribute(int index); + + DynamicStat & getHealth(); + + DynamicStat & getMagicka(); + + DynamicStat & getFatigue(); + + DynamicStat & getDynamic(int index); + + Spells & getSpells(); + + ActiveSpells & getActiveSpells(); + + MagicEffects & getMagicEffects(); + + + void setAttribute(int index, const Stat &value); + + void setHealth(const DynamicStat &value); + + void setMagicka(const DynamicStat &value); + + void setFatigue(const DynamicStat &value); + + void setSpells(const Spells &spells); + + void setActiveSpells(const ActiveSpells &active); + + void setMagicEffects(const MagicEffects &effects); + + void setLevel(int level); + + void setHello(int value); + + void setFight(int value); + + void setFlee(int value); + + void setAlarm(int value); }; + + // Inline const getters + + inline const Stat & + CreatureStats::getAttribute(int index) const { + if (index < 0 || index > 7) { + throw std::runtime_error("attribute index is out of range"); + } + return mAttributes[index]; + } + + inline const DynamicStat & + CreatureStats::getHealth() const { + return mDynamic[0]; + } + + inline const DynamicStat & + CreatureStats::getMagicka() const { + return mDynamic[1]; + } + + inline const DynamicStat & + CreatureStats::getFatigue() const { + return mDynamic[2]; + } + + inline const Spells & + CreatureStats::getSpells() const { + return mSpells; + } + + inline const ActiveSpells & + CreatureStats::getActiveSpells() const { + return mActiveSpells; + } + + inline const MagicEffects & + CreatureStats::getMagicEffects() const { + return mMagicEffects; + } + + inline int + CreatureStats::getLevel() const { + return mLevel; + } + + inline int + CreatureStats::getHello() const { + return mHello; + } + + inline int + CreatureStats::getFight() const { + return mFight; + } + + inline int + CreatureStats::getFlee() const { + return mFlee; + } + + inline int + CreatureStats::getAlarm() const { + return mAlarm; + } + + // Inline non-const getters + + inline Stat & + CreatureStats::getAttribute(int index) { + if (index < 0 || index > 7) { + throw std::runtime_error("attribute index is out of range"); + } + return mAttributes[index]; + } + + inline DynamicStat & + CreatureStats::getHealth() { + return mDynamic[0]; + } + + inline DynamicStat & + CreatureStats::getMagicka() { + return mDynamic[1]; + } + + inline DynamicStat & + CreatureStats::getFatigue() { + return mDynamic[2]; + } + + inline DynamicStat & + CreatureStats::getDynamic(int index) { + if (index < 0 || index > 2) { + throw std::runtime_error("dynamic stat index is out of range"); + } + return mDynamic[index]; + } + + inline Spells & + CreatureStats::getSpells() { + return mSpells; + } + + inline void + CreatureStats::setSpells(const Spells &spells) { + mSpells = spells; + } + + inline ActiveSpells & + CreatureStats::getActiveSpells() { + return mActiveSpells; + } + + inline MagicEffects & + CreatureStats::getMagicEffects() { + return mMagicEffects; + } + + // Inline setters + + inline void + CreatureStats::setAttribute(int index, const Stat &value) { + if (index < 0 || index > 7) { + throw std::runtime_error("attribute index is out of range"); + } + mAttributes[index] = value; + } + + inline void + CreatureStats::setHealth(const DynamicStat &value) { + mDynamic[0] = value; + } + + inline void + CreatureStats::setMagicka(const DynamicStat &value) { + mDynamic[1] = value; + } + + inline void + CreatureStats::setFatigue(const DynamicStat &value) { + mDynamic[2] = value; + } + + inline void + CreatureStats::setLevel(int level) { + mLevel = level; + } + + inline void + CreatureStats::setActiveSpells(const ActiveSpells &active) { + mActiveSpells = active; + } + + inline void + CreatureStats::setMagicEffects(const MagicEffects &effects) { + mMagicEffects = effects; + } + + inline void + CreatureStats::setHello(int value) { + mHello = value; + } + + inline void + CreatureStats::setFight(int value) { + mFight = value; + } + + inline void + CreatureStats::setFlee(int value) { + mFlee = value; + } + + inline void + CreatureStats::setAlarm(int value) { + mAlarm = value; + } } #endif diff --git a/apps/openmw/mwmechanics/drawstate.hpp b/apps/openmw/mwmechanics/drawstate.hpp index 772086d90..112b6e4f9 100644 --- a/apps/openmw/mwmechanics/drawstate.hpp +++ b/apps/openmw/mwmechanics/drawstate.hpp @@ -1,13 +1,15 @@ #ifndef GAME_MWMECHANICS_DRAWSTATE_H #define GAME_MWMECHANICS_DRAWSTATE_H -#undef DrawState - -enum DrawState +namespace MWMechanics { - DrawState_Weapon = 0, - DrawState_Spell = 1, - DrawState_Nothing = 2, -}; + /// \note The _ suffix is required to avoid a collision with a Windoze macro. Die, Microsoft! Die! + enum DrawState_ + { + DrawState_Weapon = 0, + DrawState_Spell = 1, + DrawState_Nothing = 2, + }; +} #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanager.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp similarity index 72% rename from apps/openmw/mwmechanics/mechanicsmanager.cpp rename to apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 331074ef7..7fd0b29c3 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1,14 +1,13 @@ -#include "mechanicsmanager.hpp" +#include "mechanicsmanagerimp.hpp" #include -#include "../mwgui/window_manager.hpp" - #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/player.hpp" namespace MWMechanics @@ -23,21 +22,21 @@ namespace MWMechanics const ESM::NPC *player = ptr.get()->base; // reset - creatureStats.mLevel = player->npdt52.level; - creatureStats.mSpells.clear(); - creatureStats.mMagicEffects = MagicEffects(); + creatureStats.setLevel(player->npdt52.level); + creatureStats.getSpells().clear(); + creatureStats.setMagicEffects(MagicEffects()); for (int i=0; i<27; ++i) - npcStats.mSkill[i].setBase (player->npdt52.skills[i]); + npcStats.getSkill (i).setBase (player->npdt52.skills[i]); - creatureStats.mAttributes[0].setBase (player->npdt52.strength); - creatureStats.mAttributes[1].setBase (player->npdt52.intelligence); - creatureStats.mAttributes[2].setBase (player->npdt52.willpower); - creatureStats.mAttributes[3].setBase (player->npdt52.agility); - creatureStats.mAttributes[4].setBase (player->npdt52.speed); - creatureStats.mAttributes[5].setBase (player->npdt52.endurance); - creatureStats.mAttributes[6].setBase (player->npdt52.personality); - creatureStats.mAttributes[7].setBase (player->npdt52.luck); + creatureStats.getAttribute(0).setBase (player->npdt52.strength); + creatureStats.getAttribute(1).setBase (player->npdt52.intelligence); + creatureStats.getAttribute(2).setBase (player->npdt52.willpower); + creatureStats.getAttribute(3).setBase (player->npdt52.agility); + creatureStats.getAttribute(4).setBase (player->npdt52.speed); + creatureStats.getAttribute(5).setBase (player->npdt52.endurance); + creatureStats.getAttribute(6).setBase (player->npdt52.personality); + creatureStats.getAttribute(7).setBase (player->npdt52.luck); // race if (mRaceSelected) @@ -63,7 +62,7 @@ namespace MWMechanics case 7: attribute = &race->data.luck; break; } - creatureStats.mAttributes[i].setBase ( + creatureStats.getAttribute(i).setBase ( static_cast (male ? attribute->male : attribute->female)); } @@ -73,15 +72,15 @@ namespace MWMechanics if (index>=0 && index<27) { - npcStats.mSkill[index].setBase ( - npcStats.mSkill[index].getBase() + race->data.bonus[i].bonus); + npcStats.getSkill (index).setBase ( + npcStats.getSkill (index).getBase() + race->data.bonus[i].bonus); } } for (std::vector::const_iterator iter (race->powers.list.begin()); iter!=race->powers.list.end(); ++iter) { - creatureStats.mSpells.add (*iter); + creatureStats.getSpells().add (*iter); } } @@ -95,7 +94,7 @@ namespace MWMechanics for (std::vector::const_iterator iter (sign->powers.list.begin()); iter!=sign->powers.list.end(); ++iter) { - creatureStats.mSpells.add (*iter); + creatureStats.getSpells().add (*iter); } } @@ -109,8 +108,8 @@ namespace MWMechanics int attribute = class_.data.attribute[i]; if (attribute>=0 && attribute<8) { - creatureStats.mAttributes[attribute].setBase ( - creatureStats.mAttributes[attribute].getBase() + 10); + creatureStats.getAttribute(attribute).setBase ( + creatureStats.getAttribute(attribute).getBase() + 10); } } @@ -124,8 +123,8 @@ namespace MWMechanics if (index>=0 && index<27) { - npcStats.mSkill[index].setBase ( - npcStats.mSkill[index].getBase() + bonus); + npcStats.getSkill (index).setBase ( + npcStats.getSkill (index).getBase() + bonus); } } } @@ -141,8 +140,8 @@ namespace MWMechanics if (index>=0 && index<27) { - npcStats.mSkill[index].setBase ( - npcStats.mSkill[index].getBase() + 5); + npcStats.getSkill (index).setBase ( + npcStats.getSkill (index).getBase() + 5); } } } @@ -151,8 +150,9 @@ namespace MWMechanics // forced update and current value adjustments mActors.updateActor (ptr, 0); - for (int i=0; i<3; ++i) - creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified()); + creatureStats.getHealth().setCurrent(creatureStats.getHealth().getModified()); + creatureStats.getMagicka().setCurrent(creatureStats.getMagicka().getModified()); + creatureStats.getFatigue().setCurrent(creatureStats.getFatigue().getModified()); } @@ -213,22 +213,25 @@ namespace MWMechanics for (int i=0; i<8; ++i) { - if (stats.mAttributes[i]!=mWatchedCreature.mAttributes[i]) + if (stats.getAttribute(i)!=mWatchedCreature.getAttribute(i)) { - mWatchedCreature.mAttributes[i] = stats.mAttributes[i]; + mWatchedCreature.setAttribute(i, stats.getAttribute(i)); - MWBase::Environment::get().getWindowManager()->setValue (attributeNames[i], stats.mAttributes[i]); + MWBase::Environment::get().getWindowManager()->setValue (attributeNames[i], stats.getAttribute(i)); } } - for (int i=0; i<3; ++i) - { - if (stats.mDynamic[i]!=mWatchedCreature.mDynamic[i]) - { - mWatchedCreature.mDynamic[i] = stats.mDynamic[i]; - - MWBase::Environment::get().getWindowManager()->setValue (dynamicNames[i], stats.mDynamic[i]); - } + if (stats.getHealth() != mWatchedCreature.getHealth()) { + mWatchedCreature.setHealth(stats.getHealth()); + MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[0], stats.getHealth()); + } + if (stats.getMagicka() != mWatchedCreature.getMagicka()) { + mWatchedCreature.setMagicka(stats.getMagicka()); + MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[1], stats.getMagicka()); + } + if (stats.getFatigue() != mWatchedCreature.getFatigue()) { + mWatchedCreature.setFatigue(stats.getFatigue()); + MWBase::Environment::get().getWindowManager()->setValue(dynamicNames[2], stats.getFatigue()); } bool update = false; @@ -236,18 +239,18 @@ namespace MWMechanics //Loop over ESM::Skill::SkillEnum for(int i = 0; i < 27; ++i) { - if(npcStats.mSkill[i] != mWatchedNpc.mSkill[i]) + if(npcStats.getSkill (i) != mWatchedNpc.getSkill (i)) { update = true; - mWatchedNpc.mSkill[i] = npcStats.mSkill[i]; - MWBase::Environment::get().getWindowManager()->setValue((ESM::Skill::SkillEnum)i, npcStats.mSkill[i]); + mWatchedNpc.getSkill (i) = npcStats.getSkill (i); + MWBase::Environment::get().getWindowManager()->setValue((ESM::Skill::SkillEnum)i, npcStats.getSkill (i)); } } if (update) MWBase::Environment::get().getWindowManager()->updateSkillArea(); - MWBase::Environment::get().getWindowManager()->setValue ("level", stats.mLevel); + MWBase::Environment::get().getWindowManager()->setValue ("level", stats.getLevel()); } if (mUpdatePlayer) @@ -261,8 +264,8 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getPlayer().getClass().name); mUpdatePlayer = false; - MWGui::WindowManager::SkillList majorSkills (5); - MWGui::WindowManager::SkillList minorSkills (5); + MWBase::WindowManager::SkillList majorSkills (5); + MWBase::WindowManager::SkillList minorSkills (5); for (int i=0; i<5; ++i) { diff --git a/apps/openmw/mwmechanics/mechanicsmanager.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp similarity index 58% rename from apps/openmw/mwmechanics/mechanicsmanager.hpp rename to apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 62bb4cf7e..d5fd3b6f2 100644 --- a/apps/openmw/mwmechanics/mechanicsmanager.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -1,8 +1,7 @@ -#ifndef GAME_MWMECHANICS_MECHANICSMANAGER_H -#define GAME_MWMECHANICS_MECHANICSMANAGER_H +#ifndef GAME_MWMECHANICS_MECHANICSMANAGERIMP_H +#define GAME_MWMECHANICS_MECHANICSMANAGERIMP_H -#include -#include +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/ptr.hpp" @@ -15,9 +14,14 @@ namespace Ogre class Vector3; } +namespace MWWorld +{ + class CellStore; +} + namespace MWMechanics { - class MechanicsManager + class MechanicsManager : public MWBase::MechanicsManager { MWWorld::Ptr mWatched; CreatureStats mWatchedCreature; @@ -33,43 +37,41 @@ namespace MWMechanics public: - MechanicsManager (); + MechanicsManager(); - void configureGUI(); - - void addActor (const MWWorld::Ptr& ptr); + virtual void addActor (const MWWorld::Ptr& ptr); ///< Register an actor for stats management - void removeActor (const MWWorld::Ptr& ptr); + virtual void removeActor (const MWWorld::Ptr& ptr); ///< Deregister an actor for stats management - void dropActors (const MWWorld::Ptr::CellStore *cellStore); + virtual void dropActors (const MWWorld::CellStore *cellStore); ///< Deregister all actors in the given cell. - void watchActor (const MWWorld::Ptr& ptr); + virtual void watchActor (const MWWorld::Ptr& ptr); ///< On each update look for changes in a previously registered actor and update the /// GUI accordingly. - void update (std::vector >& movement, float duration, - bool paused); + virtual void update (std::vector >& movement, + float duration, bool paused); ///< Update actor stats and store desired velocity vectors in \a movement /// /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). - void setPlayerName (const std::string& name); + virtual void setPlayerName (const std::string& name); ///< Set player name. - void setPlayerRace (const std::string& id, bool male); + virtual void setPlayerRace (const std::string& id, bool male); ///< Set player race. - void setPlayerBirthsign (const std::string& id); + virtual void setPlayerBirthsign (const std::string& id); ///< Set player birthsign. - void setPlayerClass (const std::string& id); + virtual void setPlayerClass (const std::string& id); ///< Set player class to stock class. - void setPlayerClass (const ESM::Class& class_); + virtual void setPlayerClass (const ESM::Class& class_); ///< Set player class to custom class. }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp new file mode 100644 index 000000000..d2908e26e --- /dev/null +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -0,0 +1,140 @@ + +#include "npcstats.hpp" + +#include +#include + +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +MWMechanics::NpcStats::NpcStats() +: mMovementFlags (0), mDrawState (DrawState_Nothing) +{} + +MWMechanics::DrawState_ MWMechanics::NpcStats::getDrawState() const +{ + return mDrawState; +} + +void MWMechanics::NpcStats::setDrawState (DrawState_ state) +{ + mDrawState = state; +} + +bool MWMechanics::NpcStats::getMovementFlag (Flag flag) const +{ + return mMovementFlags & flag; +} + +void MWMechanics::NpcStats::setMovementFlag (Flag flag, bool state) +{ + if (state) + mMovementFlags |= flag; + else + mMovementFlags &= ~flag; +} + +const MWMechanics::Stat& MWMechanics::NpcStats::getSkill (int index) const +{ + if (index<0 || index>=27) + throw std::runtime_error ("skill index out of range"); + + return mSkill[index]; +} + +MWMechanics::Stat& MWMechanics::NpcStats::getSkill (int index) +{ + if (index<0 || index>=27) + throw std::runtime_error ("skill index out of range"); + + return mSkill[index]; +} + +std::map& MWMechanics::NpcStats::getFactionRanks() +{ + return mFactionRank; +} + +const std::map& MWMechanics::NpcStats::getFactionRanks() const +{ + return mFactionRank; +} + +float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, + int level) const +{ + if (level<0) + level = static_cast (getSkill (skillIndex).getBase()); + + const ESM::Skill *skill = MWBase::Environment::get().getWorld()->getStore().skills.find (skillIndex); + + float skillFactor = 1; + + if (usageType>=4) + throw std::runtime_error ("skill usage type out of range"); + + if (usageType>0) + { + skillFactor = skill->data.useValue[usageType]; + + if (skillFactor<=0) + throw std::runtime_error ("invalid skill gain factor"); + } + + float typeFactor = + MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fMiscSkillBonus")->f; + + for (int i=0; i<5; ++i) + if (class_.data.skills[i][0]==skillIndex) + { + typeFactor = + MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fMinorSkillBonus")->f; + + break; + } + + for (int i=0; i<5; ++i) + if (class_.data.skills[i][1]==skillIndex) + { + typeFactor = + MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fMajorSkillBonus")->f; + + break; + } + + if (typeFactor<=0) + throw std::runtime_error ("invalid skill type factor"); + + float specialisationFactor = 1; + + if (skill->data.specialization==class_.data.specialization) + { + specialisationFactor = + MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fSpecialSkillBonus")->f; + + if (specialisationFactor<=0) + throw std::runtime_error ("invalid skill specialisation factor"); + } + + return 1.0 / (level +1) * (1.0 / skillFactor) * typeFactor * specialisationFactor; +} + +void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType) +{ + float base = getSkill (skillIndex).getBase(); + + int level = static_cast (base); + + base += getSkillGain (skillIndex, class_, usageType); + + if (static_cast (base)!=level) + base = level+1; + + getSkill (skillIndex).setBase (base); +} diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 972863b72..364dab03f 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -3,10 +3,16 @@ #include #include +#include #include "stat.hpp" #include "drawstate.hpp" +namespace ESM +{ + struct Class; +} + namespace MWMechanics { /// \brief Additional stats for NPCs @@ -16,24 +22,57 @@ namespace MWMechanics /// \note For technical reasons the spell list and the currently selected spell is also handled by /// CreatureStats, even though they are actually NPC stats. - struct NpcStats + class NpcStats { - // NPCs other than the player can only have one faction. But for the sake of consistency - // we use the same data structure for the PC and the NPCs. - /// \note the faction key must be in lowercase - std::map mFactionRank; + public: - Stat mSkill[27]; + enum Flag + { + Flag_ForceRun = 1, + Flag_ForceSneak = 2, + Flag_Run = 4, + Flag_Sneak = 8 + }; - bool mForceRun; - bool mForceSneak; - bool mRun; - bool mSneak; - bool mCombat; - DrawState mDrawState; + private: - NpcStats() : mForceRun (false), mForceSneak (false), mRun (false), mSneak (false), - mCombat (false) , mDrawState(DrawState_Nothing) {} + /// NPCs other than the player can only have one faction. But for the sake of consistency + /// we use the same data structure for the PC and the NPCs. + /// \note the faction key must be in lowercase + std::map mFactionRank; + + DrawState_ mDrawState; + unsigned int mMovementFlags; + Stat mSkill[27]; + + public: + + NpcStats(); + + DrawState_ getDrawState() const; + + void setDrawState (DrawState_ state); + + bool getMovementFlag (Flag flag) const; + + void setMovementFlag (Flag flag, bool state); + + const Stat& getSkill (int index) const; + + Stat& getSkill (int index); + + std::map& getFactionRanks(); + + const std::map& getFactionRanks() const; + + float getSkillGain (int skillIndex, const ESM::Class& class_, int usageType = -1, + int level = -1) const; + ///< \param usageType: Usage specific factor, specified in the respective skill record; + /// -1: use a factor of 1.0 instead. + /// \param level Level to base calculation on; -1: use current level. + + void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1); + ///< Increase skill by usage. }; } diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 70eb78639..5d21d96d0 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -1,11 +1,12 @@ #include "spells.hpp" +#include + #include #include "../mwbase/environment.hpp" - -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" #include "magiceffects.hpp" diff --git a/apps/openmw/mwmechanics/spellsuccess.hpp b/apps/openmw/mwmechanics/spellsuccess.hpp index 11ac7cda7..1ab1bb11f 100644 --- a/apps/openmw/mwmechanics/spellsuccess.hpp +++ b/apps/openmw/mwmechanics/spellsuccess.hpp @@ -1,9 +1,11 @@ #ifndef MWMECHANICS_SPELLSUCCESS_H #define MWMECHANICS_SPELLSUCCESS_H -#include "../mwworld/ptr.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" + +#include "../mwworld/ptr.hpp" +#include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" #include "npcstats.hpp" @@ -39,7 +41,7 @@ namespace MWMechanics { const ESM::MagicEffect* effect = MWBase::Environment::get().getWorld()->getStore().magicEffects.find(it->effectID); int _school = effect->data.school; - int _skillLevel = stats.mSkill[spellSchoolToSkill(_school)].getModified(); + int _skillLevel = stats.getSkill (spellSchoolToSkill(_school)).getModified(); if (school == -1) { @@ -76,15 +78,15 @@ namespace MWMechanics NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor); CreatureStats& creatureStats = MWWorld::Class::get(actor).getCreatureStats(actor); - int skillLevel = stats.mSkill[getSpellSchool(spellId, actor)].getModified(); + int skillLevel = stats.getSkill (getSpellSchool(spellId, actor)).getModified(); // Sound magic effect (reduces spell casting chance) - int soundMagnitude = creatureStats.mMagicEffects.get (MWMechanics::EffectKey (48)).mMagnitude; + int soundMagnitude = creatureStats.getMagicEffects().get (MWMechanics::EffectKey (48)).mMagnitude; - int willpower = creatureStats.mAttributes[ESM::Attribute::Willpower].getModified(); - int luck = creatureStats.mAttributes[ESM::Attribute::Luck].getModified(); - int currentFatigue = creatureStats.mDynamic[2].getCurrent(); - int maxFatigue = creatureStats.mDynamic[2].getModified(); + int willpower = creatureStats.getAttribute(ESM::Attribute::Willpower).getModified(); + int luck = creatureStats.getAttribute(ESM::Attribute::Luck).getModified(); + int currentFatigue = creatureStats.getFatigue().getCurrent(); + int maxFatigue = creatureStats.getFatigue().getModified(); int spellCost = spell->data.cost; // There we go, all needed variables are there, lets go diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 2449075a8..d576020c5 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -31,6 +31,11 @@ namespace MWMechanics return mModified; } + T getModifier() const + { + return mModified-mBase; + } + /// Set base and modified to \a value. void set (const T& value) { @@ -65,10 +70,9 @@ namespace MWMechanics mBase += diff; } - /// Change modified relatively. - void modify (const T& diff) + void setModifier (const T& modifier) { - mModified += diff; + mModified = mBase + modifier; } }; @@ -143,7 +147,7 @@ namespace MWMechanics void modify (const T& diff) { mStatic.modify (diff); - modifyCurrent (diff); + setCurrent (getCurrent()+diff); } void setCurrent (const T& value) @@ -155,6 +159,13 @@ namespace MWMechanics else if (mCurrent>getModified()) mCurrent = getModified(); } + + void setModifier (const T& modifier) + { + T diff = modifier - mStatic.getModifier(); + mStatic.setModifier (modifier); + setCurrent (getCurrent()+diff); + } }; template diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 152cf3277..415d17241 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -1,7 +1,7 @@ #include "actors.hpp" + #include - - +#include using namespace Ogre; @@ -122,15 +122,35 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store){ void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){ if(mAllActors.find(ptr) != mAllActors.end()) - mAllActors[ptr]->startScript(groupName, mode, number); + mAllActors[ptr]->playGroup(groupName, mode, number); } void Actors::skipAnimation (const MWWorld::Ptr& ptr){ if(mAllActors.find(ptr) != mAllActors.end()) - mAllActors[ptr]->stopScript(); + mAllActors[ptr]->skipAnim(); } void Actors::update (float duration){ for(std::map::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++) - { - (iter->second)->runAnimation(duration); - } + iter->second->runAnimation(duration); +} + +void +Actors::updateObjectCell(const MWWorld::Ptr &ptr) +{ + Ogre::SceneNode *node; + MWWorld::CellStore *newCell = ptr.getCell(); + + if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { + node = mMwRoot->createChildSceneNode(); + mCellSceneNodes[newCell] = node; + } else { + node = mCellSceneNodes[newCell]; + } + node->addChild(ptr.getRefData().getBaseNode()); + if (mAllActors.find(ptr) != mAllActors.end()) { + /// \note Update key (Ptr's are compared only with refdata so mCell + /// on key is outdated), maybe redundant + Animation *anim = mAllActors[ptr]; + mAllActors.erase(ptr); + mAllActors[ptr] = anim; + } } diff --git a/apps/openmw/mwrender/actors.hpp b/apps/openmw/mwrender/actors.hpp index 432bcc297..073c5d51f 100644 --- a/apps/openmw/mwrender/actors.hpp +++ b/apps/openmw/mwrender/actors.hpp @@ -1,28 +1,21 @@ #ifndef _GAME_RENDER_ACTORS_H #define _GAME_RENDER_ACTORS_H -#include "components/esm_store/cell_store.hpp" -#include -#include - - - -#include -#include "components/nifogre/ogre_nif_loader.hpp" - -#include "../mwworld/refdata.hpp" -#include "../mwworld/ptr.hpp" -#include "../mwworld/actiontalk.hpp" #include "npcanimation.hpp" #include "creatureanimation.hpp" -#include + +namespace MWWorld +{ + class Ptr; + class CellStore; +} namespace MWRender{ class Actors{ OEngine::Render::OgreRenderer &mRend; - std::map mCellSceneNodes; + std::map mCellSceneNodes; Ogre::SceneNode* mMwRoot; - std::map mAllActors; + std::map mAllActors; @@ -36,7 +29,7 @@ namespace MWRender{ bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? - void removeCell(MWWorld::Ptr::CellStore* store); + void removeCell(MWWorld::CellStore* store); void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number = 1); @@ -52,6 +45,8 @@ namespace MWRender{ void update (float duration); + /// Updates containing cell for object rendering data + void updateObjectCell(const MWWorld::Ptr &ptr); }; } #endif diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fc6258208..46f3bdc0d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1,498 +1,175 @@ #include "animation.hpp" +#include +#include +#include +#include +#include +#include -namespace MWRender{ - std::map Animation::mUniqueIDs; - Animation::Animation(OEngine::Render::OgreRenderer& _rend) - : insert(NULL) - , mRend(_rend) - , vecRotPos() - , time(0.0f) - , startTime(0.0f) - , stopTime(0.0f) - , animate(0) - , rindexI() - , tindexI() - , shapeNumber(0) - , shapeIndexI() - , shapes(NULL) - , transformations(NULL) - , textmappings(NULL) - , base(NULL) - { - } +namespace MWRender +{ - Animation::~Animation() - { - } - - std::string Animation::getUniqueID(std::string mesh){ - int counter; - std::string copy = mesh; - std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower); - if(mUniqueIDs.find(copy) == mUniqueIDs.end()){ - counter = mUniqueIDs[copy] = 0; - } - else{ - mUniqueIDs[copy] = mUniqueIDs[copy] + 1; - counter = mUniqueIDs[copy]; - } - - std::stringstream out; - if(counter > 99 && counter < 1000) - out << "0"; - else if(counter > 9) - out << "00"; - else - out << "000"; - out << counter; - return out.str(); +Animation::Animation(OEngine::Render::OgreRenderer& _rend) + : mInsert(NULL) + , mRend(_rend) + , mTime(0.0f) + , mSkipFrame(false) +{ } - void Animation::startScript(std::string groupname, int mode, int loops){ - //If groupname is recognized set animate to true - //Set the start time and stop time - //How many times to loop - if(groupname == "all"){ - animate = loops; - time = startTime; - } - else if(textmappings){ - std::string startName = groupname + ": loop start"; - std::string stopName = groupname + ": loop stop"; +Animation::~Animation() +{ + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) + sceneMgr->destroyEntity(mEntityList.mEntities[i]); + mEntityList.mEntities.clear(); +} - bool first = false; - if(loops > 1){ - startName = groupname + ": loop start"; - stopName = groupname + ": loop stop"; - - for(std::map::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){ - - std::string current = iter->first.substr(0, startName.size()); - std::transform(current.begin(), current.end(), current.begin(), ::tolower); - std::string current2 = iter->first.substr(0, stopName.size()); - std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower); - - if(current == startName){ - startTime = iter->second; - animate = loops; - time = startTime; - first = true; - } - if(current2 == stopName){ - stopTime = iter->second; - if(first) - break; - } - } - } - if(!first){ - startName = groupname + ": start"; - stopName = groupname + ": stop"; - - for(std::map::iterator iter = textmappings->begin(); iter != textmappings->end(); iter++){ - - std::string current = iter->first.substr(0, startName.size()); - std::transform(current.begin(), current.end(), current.begin(), ::tolower); - std::string current2 = iter->first.substr(0, stopName.size()); - std::transform(current2.begin(), current2.end(), current2.begin(), ::tolower); - - if(current == startName){ - startTime = iter->second; - animate = loops; - time = startTime; - first = true; - } - if(current2 == stopName){ - stopTime = iter->second; - if(first) - break; - } - } - } - - } - - } - void Animation::stopScript(){ - animate = 0; +struct checklow { + bool operator()(const char &a, const char &b) const + { + return ::tolower(a) == ::tolower(b); } +}; - void Animation::handleShapes(std::vector* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel){ - shapeNumber = 0; +bool Animation::findGroupTimes(const std::string &groupname, Animation::GroupTimes *times) +{ + const std::string &start = groupname+": start"; + const std::string &startloop = groupname+": loop start"; + const std::string &stop = groupname+": stop"; + const std::string &stoploop = groupname+": loop stop"; - if (allshapes == NULL || creaturemodel == NULL || skel == NULL) + NifOgre::TextKeyMap::const_iterator iter; + for(iter = mTextKeys.begin();iter != mTextKeys.end();iter++) + { + if(times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f) + return true; + + std::string::const_iterator strpos = iter->second.begin(); + std::string::const_iterator strend = iter->second.end(); + + while(strpos != strend) { - return; + size_t strlen = strend-strpos; + std::string::const_iterator striter; + + if(start.size() <= strlen && + ((striter=std::mismatch(strpos, strend, start.begin(), checklow()).first) == strend || + *striter == '\r' || *striter == '\n')) + { + times->mStart = iter->first; + times->mLoopStart = iter->first; + } + else if(startloop.size() <= strlen && + ((striter=std::mismatch(strpos, strend, startloop.begin(), checklow()).first) == strend || + *striter == '\r' || *striter == '\n')) + { + times->mLoopStart = iter->first; + } + else if(stoploop.size() <= strlen && + ((striter=std::mismatch(strpos, strend, stoploop.begin(), checklow()).first) == strend || + *striter == '\r' || *striter == '\n')) + { + times->mLoopStop = iter->first; + } + else if(stop.size() <= strlen && + ((striter=std::mismatch(strpos, strend, stop.begin(), checklow()).first) == strend || + *striter == '\r' || *striter == '\n')) + { + times->mStop = iter->first; + if(times->mLoopStop < 0.0f) + times->mLoopStop = iter->first; + break; + } + + strpos = std::find(strpos+1, strend, '\n'); + while(strpos != strend && *strpos == '\n') + strpos++; + } + } + + return (times->mStart >= 0.0f && times->mLoopStart >= 0.0f && times->mLoopStop >= 0.0f && times->mStop >= 0.0f); +} + + +void Animation::playGroup(std::string groupname, int mode, int loops) +{ + GroupTimes times; + times.mLoops = loops; + + if(groupname == "all") + { + times.mStart = times.mLoopStart = 0.0f; + times.mLoopStop = times.mStop = 0.0f; + + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + times.mLoopStop = times.mStop = state->getLength(); + break; + } + } + } + else if(!findGroupTimes(groupname, ×)) + throw std::runtime_error("Failed to find animation group "+groupname); + + if(mode == 0 && mCurGroup.mLoops > 0) + mNextGroup = times; + else + { + mCurGroup = times; + mNextGroup = GroupTimes(); + mTime = ((mode==2) ? mCurGroup.mLoopStart : mCurGroup.mStart); + } +} + +void Animation::skipAnim() +{ + mSkipFrame = true; +} + +void Animation::runAnimation(float timepassed) +{ + if(mCurGroup.mLoops > 0 && !mSkipFrame) + { + mTime += timepassed; + if(mTime >= mCurGroup.mLoopStop) + { + if(mCurGroup.mLoops > 1) + { + mCurGroup.mLoops--; + mTime = mTime - mCurGroup.mLoopStop + mCurGroup.mLoopStart; + } + else if(mTime >= mCurGroup.mStop) + { + if(mNextGroup.mLoops > 0) + mTime = mTime - mCurGroup.mStop + mNextGroup.mStart; + else + mTime = mCurGroup.mStop; + mCurGroup = mNextGroup; + mNextGroup = GroupTimes(); + } } - std::vector::iterator allshapesiter; - for(allshapesiter = allshapes->begin(); allshapesiter != allshapes->end(); allshapesiter++) - - { - //std::map vecPosRot; - - Nif::NiTriShapeCopy& copy = *allshapesiter; - std::vector* allvertices = ©.vertices; - - - - //std::set vertices; - //std::set normals; - //std::vector boneinfovector = copy.boneinfo; - std::map >* verticesToChange = ©.vertsToWeights; - - //std::cout << "Name " << copy.sname << "\n"; - Ogre::HardwareVertexBufferSharedPtr vbuf = creaturemodel->getMesh()->getSubMesh(copy.sname)->vertexData->vertexBufferBinding->getBuffer(0); - Ogre::Real* pReal = static_cast(vbuf->lock(Ogre::HardwareBuffer::HBL_NORMAL)); - - - std::vector initialVertices = copy.morph.getInitialVertices(); - //Each shape has multiple indices - if(initialVertices.size() ) - { - - if(copy.vertices.size() == initialVertices.size()) - { - //Create if it doesn't already exist - if(shapeIndexI.size() == static_cast (shapeNumber)) - { - std::vector vec; - shapeIndexI.push_back(vec); - } - if(time >= copy.morph.getStartTime() && time <= copy.morph.getStopTime()){ - float x; - for (unsigned int i = 0; i < copy.morph.getAdditionalVertices().size(); i++){ - int j = 0; - if(shapeIndexI[shapeNumber].size() <= i) - shapeIndexI[shapeNumber].push_back(0); - - - if(timeIndex(time,copy.morph.getRelevantTimes()[i],(shapeIndexI[shapeNumber])[i], j, x)){ - int indexI = (shapeIndexI[shapeNumber])[i]; - std::vector relevantData = (copy.morph.getRelevantData()[i]); - float v1 = relevantData[indexI].x; - float v2 = relevantData[j].x; - float t = v1 + (v2 - v1) * x; - if ( t < 0 ) t = 0; - if ( t > 1 ) t = 1; - if( t != 0 && initialVertices.size() == copy.morph.getAdditionalVertices()[i].size()) - { - for (unsigned int v = 0; v < initialVertices.size(); v++){ - initialVertices[v] += ((copy.morph.getAdditionalVertices()[i])[v]) * t; - } - } - - } - - - - } - - allvertices = &initialVertices; - } - shapeNumber++; - } - } - - - if(verticesToChange->size() > 0){ - - for(std::map >::iterator iter = verticesToChange->begin(); - iter != verticesToChange->end(); iter++) - { - std::vector inds = iter->second; - int verIndex = iter->first; - Ogre::Vector3 currentVertex = (*allvertices)[verIndex]; - Nif::NiSkinData::BoneInfoCopy* boneinfocopy = &(allshapesiter->boneinfo[inds[0].boneinfocopyindex]); - Ogre::Bone *bonePtr = 0; - - - - Ogre::Vector3 vecPos; - Ogre::Quaternion vecRot; - std::map::iterator result = vecRotPos.find(boneinfocopy); - - if(result == vecRotPos.end()){ - bonePtr = skel->getBone(boneinfocopy->bonename); - - vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans; - vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation; - - - PosAndRot both; - both.vecPos = vecPos; - both.vecRot = vecRot; - vecRotPos[boneinfocopy] = both; - - } - else{ - PosAndRot both = result->second; - vecPos = both.vecPos; - vecRot = both.vecRot; - } - - Ogre::Vector3 absVertPos = (vecPos + vecRot * currentVertex) * inds[0].weight; - - - - for(std::size_t i = 1; i < inds.size(); i++){ - boneinfocopy = &(allshapesiter->boneinfo[inds[i].boneinfocopyindex]); - result = vecRotPos.find(boneinfocopy); - - - if(result == vecRotPos.end()){ - bonePtr = skel->getBone(boneinfocopy->bonename); - vecPos = bonePtr->_getDerivedPosition() + bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.trans; - vecRot = bonePtr->_getDerivedOrientation() * boneinfocopy->trafo.rotation; - - PosAndRot both; - both.vecPos = vecPos; - both.vecRot = vecRot; - vecRotPos[boneinfocopy] = both; - - } - else{ - PosAndRot both = result->second; - vecPos = both.vecPos; - vecRot = both.vecRot; - } - - - absVertPos += (vecPos + vecRot * currentVertex) * inds[i].weight; - - - } - Ogre::Real* addr = (pReal + 3 * verIndex); - *addr = absVertPos.x; - *(addr+1) = absVertPos.y; - *(addr+2) = absVertPos.z; - - } - - - - - } - else - { - //Ogre::Bone *bonePtr = creaturemodel->getSkeleton()->getBone(copy.bonename); - Ogre::Quaternion shaperot = copy.trafo.rotation; - Ogre::Vector3 shapetrans = copy.trafo.trans; - float shapescale = copy.trafo.scale; - std::vector boneSequence = copy.boneSequence; - - Ogre::Vector3 transmult; - Ogre::Quaternion rotmult; - float scale; - if(boneSequence.size() > 0){ - std::vector::iterator boneSequenceIter = boneSequence.begin(); - if(skel->hasBone(*boneSequenceIter)){ - Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter); - - - - - transmult = bonePtr->getPosition(); - rotmult = bonePtr->getOrientation(); - scale = bonePtr->getScale().x; - boneSequenceIter++; - - for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++) - { - if(skel->hasBone(*boneSequenceIter)){ - Ogre::Bone *bonePtr = skel->getBone(*boneSequenceIter); - // Computes C = B + AxC*scale - transmult = transmult + rotmult * bonePtr->getPosition(); - rotmult = rotmult * bonePtr->getOrientation(); - scale = scale * bonePtr->getScale().x; - } - //std::cout << "Bone:" << *boneSequenceIter << " "; - } - transmult = transmult + rotmult * shapetrans; - rotmult = rotmult * shaperot; - scale = shapescale * scale; - - //std::cout << "Position: " << transmult << "Rotation: " << rotmult << "\n"; - } - } - else - { - transmult = shapetrans; - rotmult = shaperot; - scale = shapescale; - } - - - - - // Computes C = B + AxC*scale - // final_vector = old_vector + old_rotation*new_vector*old_scale/ - - for(unsigned int i = 0; i < allvertices->size(); i++){ - Ogre::Vector3 current = transmult + rotmult * (*allvertices)[i]; - Ogre::Real* addr = pReal + i * 3; - *addr = current.x; - *(addr+1) = current.y; - *(addr + 2) = current.z; - - }/* - for(int i = 0; i < allnormals.size(); i++){ - Ogre::Vector3 current =rotmult * allnormals[i]; - Ogre::Real* addr = pRealNormal + i * 3; - *addr = current.x; - *(addr+1) = current.y; - *(addr + 2) = current.z; - - }*/ - - } - vbuf->unlock(); - - } - + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setTimePosition(mTime); + } + } } - bool Animation::timeIndex( float time, const std::vector & times, int & i, int & j, float & x ){ - int count; - if ( (count = times.size()) > 0 ) - { - if ( time <= times[0] ) - { - i = j = 0; - x = 0.0; - return true; - } - if ( time >= times[count - 1] ) - { - i = j = count - 1; - x = 0.0; - return true; - } - - if ( i < 0 || i >= count ) - i = 0; - - float tI = times[i]; - if ( time > tI ) - { - j = i + 1; - float tJ; - while ( time >= ( tJ = times[j]) ) - { - i = j++; - tI = tJ; - } - x = ( time - tI ) / ( tJ - tI ); - return true; - } - else if ( time < tI ) - { - j = i - 1; - float tJ; - while ( time <= ( tJ = times[j] ) ) - { - i = j--; - tI = tJ; - } - x = ( time - tI ) / ( tJ - tI ); - return true; - } - else - { - j = i; - x = 0.0; - return true; - } - } - else - return false; - -} - - void Animation::handleAnimationTransforms(){ - - - Ogre::SkeletonInstance* skel = base->getSkeleton(); - - - Ogre::Bone* b = skel->getRootBone(); - b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3)); //This is a trick - - skel->_updateTransforms(); - //skel->_notifyManualBonesDirty(); - - base->getAllAnimationStates()->_notifyDirty(); - //base->_updateAnimation(); - //base->_notifyMoved(); - - - - - std::vector::iterator iter; - int slot = 0; - if(transformations){ - for(iter = transformations->begin(); iter != transformations->end(); iter++){ - if(time < iter->getStartTime() || time < startTime || time > iter->getStopTime()) - { - slot++; - continue; - } - - float x; - float x2; - - const std::vector & quats = iter->getQuat(); - - const std::vector & ttime = iter->gettTime(); - - - const std::vector & rtime = iter->getrTime(); - int rindexJ = rindexI[slot]; - - timeIndex(time, rtime, rindexI[slot], rindexJ, x2); - int tindexJ = tindexI[slot]; - - - const std::vector & translist1 = iter->getTranslist1(); - - timeIndex(time, ttime, tindexI[slot], tindexJ, x); - - Ogre::Vector3 t; - Ogre::Quaternion r; - - bool bTrans = translist1.size() > 0; - - - bool bQuats = quats.size() > 0; - - if(skel->hasBone(iter->getBonename())){ - Ogre::Bone* bone = skel->getBone(iter->getBonename()); - if(bTrans){ - Ogre::Vector3 v1 = translist1[tindexI[slot]]; - Ogre::Vector3 v2 = translist1[tindexJ]; - t = (v1 + (v2 - v1) * x); - bone->setPosition(t); - - } - if(bQuats){ - r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true); - bone->setOrientation(r); - } - - - - - - } - - - slot++; - } - skel->_updateTransforms(); - base->getAllAnimationStates()->_notifyDirty(); -} + mSkipFrame = false; } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4ab60cff4..3611d35c0 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,71 +1,57 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H -#include + +#include + +#include #include -#include "../mwworld/refdata.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" #include -#include #include -namespace MWRender{ +namespace MWRender { -struct PosAndRot{ - Ogre::Quaternion vecRot; - Ogre::Vector3 vecPos; -}; +class Animation { + struct GroupTimes { + float mStart; + float mStop; + float mLoopStart; + float mLoopStop; -class Animation{ + size_t mLoops; - protected: - Ogre::SceneNode* insert; + GroupTimes() + : mStart(-1.0f), mStop(-1.0f), mLoopStart(-1.0f), mLoopStop(-1.0f), + mLoops(0) + { } + }; + +protected: + Ogre::SceneNode* mInsert; OEngine::Render::OgreRenderer &mRend; - std::map vecRotPos; - static std::map mUniqueIDs; + float mTime; + GroupTimes mCurGroup; + GroupTimes mNextGroup; + bool mSkipFrame; + NifOgre::EntityList mEntityList; + NifOgre::TextKeyMap mTextKeys; + bool findGroupTimes(const std::string &groupname, GroupTimes *times); - float time; - float startTime; - float stopTime; - int animate; - //Represents a rotation index for each bone - std::vectorrindexI; - //Represents a translation index for each bone - std::vectortindexI; - - //Only shapes with morphing data will use a shape number - int shapeNumber; - std::vector > shapeIndexI; - - //Ogre::SkeletonInstance* skel; - std::vector* shapes; //All the NiTriShapeData for a creature - - - - std::vector* transformations; - std::map* textmappings; - Ogre::Entity* base; - void handleShapes(std::vector* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel); - void handleAnimationTransforms(); - bool timeIndex( float time, const std::vector & times, int & i, int & j, float & x ); - std::string getUniqueID(std::string mesh); - - public: - Animation(OEngine::Render::OgreRenderer& _rend); - virtual void runAnimation(float timepassed) = 0; - void startScript(std::string groupname, int mode, int loops); - void stopScript(); - - - virtual ~Animation(); +public: + Animation(OEngine::Render::OgreRenderer& _rend); + virtual ~Animation(); + void playGroup(std::string groupname, int mode, int loops); + void skipAnim(); + virtual void runAnimation(float timepassed); }; + } #endif diff --git a/apps/openmw/mwrender/compositors.cpp b/apps/openmw/mwrender/compositors.cpp index 6f97269ab..b1c98a306 100644 --- a/apps/openmw/mwrender/compositors.cpp +++ b/apps/openmw/mwrender/compositors.cpp @@ -2,6 +2,8 @@ #include #include +#include +#include using namespace MWRender; @@ -69,3 +71,38 @@ void Compositors::removeAll() mCompositors.clear(); } + +bool Compositors::anyCompositorEnabled() +{ + for (CompositorMap::iterator it=mCompositors.begin(); + it != mCompositors.end(); ++it) + { + if (it->second.first && mEnabled) + return true; + } + return false; +} + +void Compositors::countTrianglesBatches(unsigned int &triangles, unsigned int &batches) +{ + triangles = 0; + batches = 0; + + Ogre::CompositorInstance* c = NULL; + Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain (mViewport); + // accumulate tris & batches from all compositors with all their render targets + for (unsigned int i=0; i < chain->getNumCompositors(); ++i) + { + if (chain->getCompositor(i)->getEnabled()) + { + c = chain->getCompositor(i); + for (unsigned int j = 0; j < c->getTechnique()->getNumTargetPasses(); ++j) + { + std::string textureName = c->getTechnique()->getTargetPass(j)->getOutputName(); + Ogre::RenderTarget* rt = c->getRenderTarget(textureName); + triangles += rt->getTriangleCount(); + batches += rt->getBatchCount(); + } + } + } +} diff --git a/apps/openmw/mwrender/compositors.hpp b/apps/openmw/mwrender/compositors.hpp index bbd838b8e..e5dd7503c 100644 --- a/apps/openmw/mwrender/compositors.hpp +++ b/apps/openmw/mwrender/compositors.hpp @@ -44,6 +44,10 @@ namespace MWRender */ void addCompositor (const std::string& name, const int priority); + bool anyCompositorEnabled(); + + void countTrianglesBatches(unsigned int &triangles, unsigned int &batches); + void removeAll (); protected: diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 9ca3ed731..7fb153bd1 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,86 +1,77 @@ #include "creatureanimation.hpp" + +#include +#include +#include + #include "renderconst.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" using namespace Ogre; using namespace NifOgre; namespace MWRender{ -CreatureAnimation::~CreatureAnimation(){ - +CreatureAnimation::~CreatureAnimation() +{ } -CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend): Animation(_rend){ - insert = ptr.getRefData().getBaseNode(); - ESMS::LiveCellRef *ref = - ptr.get(); + +CreatureAnimation::CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend): Animation(_rend) +{ + mInsert = ptr.getRefData().getBaseNode(); + MWWorld::LiveCellRef *ref = ptr.get(); assert (ref->base != NULL); - if(!ref->base->model.empty()){ - const std::string &mesh = "meshes\\" + ref->base->model; - std::string meshNumbered = mesh + getUniqueID(mesh) + ">|"; - NifOgre::NIFLoader::load(meshNumbered); - base = mRend.getScene()->createEntity(meshNumbered); - base->setVisibilityFlags(RV_Actors); + if(!ref->base->model.empty()) + { + std::string mesh = "meshes\\" + ref->base->model; - bool transparent = false; - for (unsigned int i=0; igetNumSubEntities(); ++i) + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, mesh); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) { - Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) - { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) - { - Ogre::Pass* pass = passIt.getNext(); + Ogre::Entity *ent = mEntityList.mEntities[i]; + ent->setVisibilityFlags(RV_Actors); - if (pass->getDepthWriteEnabled() == false) - transparent = true; + bool transparent = false; + for (unsigned int j=0;j < ent->getNumSubEntities() && !transparent; ++j) + { + Ogre::MaterialPtr mat = ent->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements() && !transparent) + { + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements() && !transparent) + { + Ogre::Pass* pass = passIt.getNext(); + + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } } } + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } - base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - std::string meshZero = mesh + "0000>|"; - - if((transformations = (NIFLoader::getSingletonPtr())->getAnim(meshZero))){ - - for(std::size_t init = 0; init < transformations->size(); init++){ - rindexI.push_back(0); - tindexI.push_back(0); - } - stopTime = transformations->begin()->getStopTime(); - startTime = transformations->begin()->getStartTime(); - shapes = (NIFLoader::getSingletonPtr())->getShapes(meshZero); + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setEnabled(true); + state->setLoop(false); + } } - textmappings = NIFLoader::getSingletonPtr()->getTextIndices(meshZero); - insert->attachObject(base); } } -void CreatureAnimation::runAnimation(float timepassed){ - vecRotPos.clear(); - if(animate > 0){ - //Add the amount of time passed to time +void CreatureAnimation::runAnimation(float timepassed) +{ + // Placeholder - //Handle the animation transforms dependent on time - - //Handle the shapes dependent on animation transforms - time += timepassed; - if(time >= stopTime){ - animate--; - //std::cout << "Stopping the animation\n"; - if(animate == 0) - time = stopTime; - else - time = startTime + (time - stopTime); - } - - handleAnimationTransforms(); - handleShapes(shapes, base, base->getSkeleton()); - - } + Animation::runAnimation(timepassed); } + } diff --git a/apps/openmw/mwrender/creatureanimation.hpp b/apps/openmw/mwrender/creatureanimation.hpp index f50b7904b..b3c9d3ddd 100644 --- a/apps/openmw/mwrender/creatureanimation.hpp +++ b/apps/openmw/mwrender/creatureanimation.hpp @@ -2,11 +2,7 @@ #define _GAME_RENDER_CREATUREANIMATION_H #include "animation.hpp" -#include - -#include "../mwworld/refdata.hpp" -#include "../mwworld/ptr.hpp" #include "components/nifogre/ogre_nif_loader.hpp" @@ -17,8 +13,7 @@ class CreatureAnimation: public Animation{ public: virtual ~CreatureAnimation(); CreatureAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend); - virtual void runAnimation(float timepassed); - + virtual void runAnimation(float timepassed); }; } diff --git a/apps/openmw/mwrender/debugging.cpp b/apps/openmw/mwrender/debugging.cpp index 9086a9bc4..91b217a36 100644 --- a/apps/openmw/mwrender/debugging.cpp +++ b/apps/openmw/mwrender/debugging.cpp @@ -1,18 +1,23 @@ #include "debugging.hpp" -#include +#include #include #include #include #include +#include -#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone -#include "../mwbase/environment.hpp" -#include "../mwworld/ptr.hpp" #include #include +#include + +#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone +#include "../mwbase/environment.hpp" + +#include "../mwworld/ptr.hpp" + #include "player.hpp" using namespace Ogre; @@ -162,11 +167,11 @@ Debugging::~Debugging() bool Debugging::toggleRenderMode (int mode){ switch (mode) { - case MWWorld::World::Render_CollisionDebug: + case MWBase::World::Render_CollisionDebug: return mEngine->toggleDebugRendering(); - case MWWorld::World::Render_Pathgrid: + case MWBase::World::Render_Pathgrid: togglePathgrid(); return mPathgridEnabled; } diff --git a/apps/openmw/mwrender/debugging.hpp b/apps/openmw/mwrender/debugging.hpp index e12c0647c..d312b6d54 100644 --- a/apps/openmw/mwrender/debugging.hpp +++ b/apps/openmw/mwrender/debugging.hpp @@ -4,11 +4,15 @@ #include #include #include -#include "../mwworld/ptr.hpp" #include #include +namespace ESM +{ + struct Pathgrid; +} + namespace Ogre { class Camera; @@ -22,7 +26,8 @@ namespace Ogre namespace MWWorld { - class World; + class Ptr; + class CellStore; } namespace MWRender @@ -39,7 +44,7 @@ namespace MWRender void togglePathgrid(); - typedef std::vector CellList; + typedef std::vector CellList; CellList mActiveCells; Ogre::SceneNode *mMwRoot; @@ -50,8 +55,8 @@ namespace MWRender ExteriorPathgridNodes mExteriorPathgridNodes; Ogre::SceneNode *mInteriorPathgridNode; - void enableCellPathgrid(MWWorld::Ptr::CellStore *store); - void disableCellPathgrid(MWWorld::Ptr::CellStore *store); + void enableCellPathgrid(MWWorld::CellStore *store); + void disableCellPathgrid(MWWorld::CellStore *store); // utility void destroyCellPathgridNode(Ogre::SceneNode *node); @@ -70,8 +75,8 @@ namespace MWRender ~Debugging(); bool toggleRenderMode (int mode); - void cellAdded(MWWorld::Ptr::CellStore* store); - void cellRemoved(MWWorld::Ptr::CellStore* store); + void cellAdded(MWWorld::CellStore* store); + void cellRemoved(MWWorld::CellStore* store); }; diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 2442700bb..704a10cfe 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -1,13 +1,17 @@ #include "localmap.hpp" -#include "renderingmanager.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" -#include "../mwgui/window_manager.hpp" -#include "renderconst.hpp" #include #include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "renderconst.hpp" +#include "renderingmanager.hpp" using namespace MWRender; using namespace Ogre; @@ -226,7 +230,7 @@ void LocalMap::render(const float x, const float y, vp->setVisibilityMask(RV_Map); // use fallback techniques without shadows and without mrt - vp->setMaterialScheme("Fallback"); + vp->setMaterialScheme("local_map"); rtt->update(); diff --git a/apps/openmw/mwrender/localmap.hpp b/apps/openmw/mwrender/localmap.hpp index 9e03988f3..c5cd908fc 100644 --- a/apps/openmw/mwrender/localmap.hpp +++ b/apps/openmw/mwrender/localmap.hpp @@ -1,10 +1,15 @@ #ifndef _GAME_RENDER_LOCALMAP_H #define _GAME_RENDER_LOCALMAP_H -#include "../mwworld/ptr.hpp" - #include +#include + +namespace MWWorld +{ + class CellStore; +} + namespace MWRender { class RenderingManager; @@ -24,7 +29,7 @@ namespace MWRender * or rendered if it is not already cached. * @param exterior cell */ - void requestMap (MWWorld::Ptr::CellStore* cell); + void requestMap (MWWorld::CellStore* cell); /** * Request the local map for an interior cell. @@ -33,7 +38,7 @@ namespace MWRender * @param interior cell * @param bounding box of the cell */ - void requestMap (MWWorld::Ptr::CellStore* cell, + void requestMap (MWWorld::CellStore* cell, Ogre::AxisAlignedBox bounds); /** @@ -51,7 +56,7 @@ namespace MWRender * new cell, as well as when the game is quit. * @param current cell */ - void saveFogOfWar(MWWorld::Ptr::CellStore* cell); + void saveFogOfWar(MWWorld::CellStore* cell); private: OEngine::Render::OgreRenderer* mRendering; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5ceafca36..4f98aebc4 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -1,861 +1,584 @@ #include "npcanimation.hpp" -#include "../mwworld/world.hpp" -#include "renderconst.hpp" + +#include +#include +#include + +#include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "renderconst.hpp" using namespace Ogre; using namespace NifOgre; + namespace MWRender{ -NpcAnimation::~NpcAnimation(){ - +NpcAnimation::~NpcAnimation() +{ + removeEntities(head); + removeEntities(hair); + removeEntities(neck); + removeEntities(chest); + removeEntities(groin); + removeEntities(skirt); + removeEntities(rHand); + removeEntities(lHand); + removeEntities(rWrist); + removeEntities(lWrist); + removeEntities(rForearm); + removeEntities(lForearm); + removeEntities(rupperArm); + removeEntities(lupperArm); + removeEntities(rfoot); + removeEntities(lfoot); + removeEntities(rAnkle); + removeEntities(lAnkle); + removeEntities(rKnee); + removeEntities(lKnee); + removeEntities(rUpperLeg); + removeEntities(lUpperLeg); + removeEntities(rclavicle); + removeEntities(lclavicle); + removeEntities(tail); } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv): Animation(_rend), mStateID(-1), inv(_inv), timeToChange(0), - robe(inv.end()), helmet(inv.end()), shirt(inv.end()), - cuirass(inv.end()), greaves(inv.end()), - leftpauldron(inv.end()), rightpauldron(inv.end()), - boots(inv.end()), - leftglove(inv.end()), rightglove(inv.end()), skirtiter(inv.end()), - pants(inv.end()), - lclavicle(0), - rclavicle(0), - rupperArm(0), - lupperArm(0), - rUpperLeg(0), - lUpperLeg(0), - lForearm(0), - rForearm(0), - lWrist(0), - rWrist(0), - rKnee(0), - lKnee(0), - neck(0), - rAnkle(0), - lAnkle(0), - groin(0), - lfoot(0), - rfoot(0) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv) + : Animation(_rend), mStateID(-1), mInv(_inv), timeToChange(0), + robe(mInv.end()), helmet(mInv.end()), shirt(mInv.end()), + cuirass(mInv.end()), greaves(mInv.end()), + leftpauldron(mInv.end()), rightpauldron(mInv.end()), + boots(mInv.end()), + leftglove(mInv.end()), rightglove(mInv.end()), skirtiter(mInv.end()), + pants(mInv.end()) +{ + MWWorld::LiveCellRef *ref = ptr.get(); + + for (int init = 0; init < 27; init++) { - ESMS::LiveCellRef *ref = - ptr.get(); - Ogre::Entity* blank = 0; - std::vector* blankshape = 0; - zero = std::make_pair(blank, blankshape); - chest = std::make_pair(blank, blankshape); - tail = std::make_pair(blank, blankshape); - lFreeFoot = std::make_pair(blank, blankshape); - rFreeFoot = std::make_pair(blank, blankshape); - rhand = std::make_pair(blank, blankshape); - lhand = std::make_pair(blank, blankshape); - skirt = std::make_pair(blank, blankshape); - for (int init = 0; init < 27; init++){ - partslots[init] = -1; //each slot is empty - partpriorities[init] = 0; - } + mPartslots[init] = -1; //each slot is empty + mPartPriorities[init] = 0; + } + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.races.find(ref->base->race); - //Part selection on last character of the file string - // " Tri Chest - // * Tri Tail - // : Tri Left Foot - // < Tri Right Foot - // > Tri Left Hand - // ? Tri Right Hand - // | Normal + std::string hairID = ref->base->hair; + std::string headID = ref->base->head; + headModel = "meshes\\" + store.bodyParts.find(headID)->model; + hairModel = "meshes\\" + store.bodyParts.find(hairID)->model; + npcName = ref->base->name; - //Mirroring Parts on second to last character - //suffix == '*' - // vector = Ogre::Vector3(-1,1,1); - // suffix == '?' - // vector = Ogre::Vector3(1,-1,1); - // suffix == '<' - // vector = Ogre::Vector3(1,1,-1); + isFemale = !!(ref->base->flags&ESM::NPC::Female); + isBeast = !!(race->data.flags&ESM::Race::Beast); + bodyRaceID = "b_n_"+ref->base->race; + std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); - std::string hairID = ref->base->hair; - std::string headID = ref->base->head; - headModel = "meshes\\" + - MWBase::Environment::get().getWorld()->getStore().bodyParts.find(headID)->model; + /*std::cout << "Race: " << ref->base->race ; + if(female) + std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n"; + else + std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n"; + */ - hairModel = "meshes\\" + - MWBase::Environment::get().getWorld()->getStore().bodyParts.find(hairID)->model; - npcName = ref->base->name; + mInsert = ptr.getRefData().getBaseNode(); + assert(mInsert); - //ESMStore::Races r = - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().races.find(ref->base->race); + std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - - bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4); - char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2); - isFemale = tolower(secondtolast) == 'f'; - std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); - isBeast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_"; - - /*std::cout << "Race: " << ref->base->race ; - if(female){ - std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n"; - } - else{ - std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n"; - }*/ - - - - std::string smodel = "meshes\\base_anim.nif"; - if(isBeast) - smodel = "meshes\\base_animkna.nif"; - - insert = ptr.getRefData().getBaseNode(); - assert(insert); - - NifOgre::NIFLoader::load(smodel); - - base = mRend.getScene()->createEntity(smodel); - - base->setVisibilityFlags(RV_Actors); - bool transparent = false; - for (unsigned int i=0; igetNumSubEntities(); ++i) + mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, smodel); + for(size_t i = 0;i < mEntityList.mEntities.size();i++) { - Ogre::MaterialPtr mat = base->getSubEntity(i)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + Ogre::Entity *base = mEntityList.mEntities[i]; + + base->setVisibilityFlags(RV_Actors); + bool transparent = false; + for(unsigned int j=0;j < base->getNumSubEntities();++j) { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + Ogre::MaterialPtr mat = base->getSubEntity(j)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) { - Ogre::Pass* pass = passIt.getNext(); - - if (pass->getDepthWriteEnabled() == false) - transparent = true; - } - } - } - base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - - - base->setSkipAnimationStateUpdate(true); //Magical line of code, this makes the bones - //stay in the same place when we skipanim, or open a gui window - - - - if((transformations = (NIFLoader::getSingletonPtr())->getAnim(smodel))){ - - for(unsigned int init = 0; init < transformations->size(); init++){ - rindexI.push_back(0); - tindexI.push_back(0); - } - - stopTime = transformations->begin()->getStopTime(); - startTime = transformations->begin()->getStartTime(); - } - textmappings = NIFLoader::getSingletonPtr()->getTextIndices(smodel); - insert->attachObject(base); - - - if(isFemale) - insert->scale(race->data.height.female, race->data.height.female, race->data.height.female); - else - insert->scale(race->data.height.male, race->data.height.male, race->data.height.male); - updateParts(); - -} - -void NpcAnimation::updateParts(){ - - bool apparelChanged = false; - - - //inv.getSlot(MWWorld::InventoryStore::Slot_Robe); - if(robe != inv.getSlot(MWWorld::InventoryStore::Slot_Robe)){ - //A robe was added or removed - removePartGroup(MWWorld::InventoryStore::Slot_Robe); - robe = inv.getSlot(MWWorld::InventoryStore::Slot_Robe); - apparelChanged = true; - } - if(skirtiter != inv.getSlot(MWWorld::InventoryStore::Slot_Skirt)){ - //A robe was added or removed - removePartGroup(MWWorld::InventoryStore::Slot_Skirt); - skirtiter = inv.getSlot(MWWorld::InventoryStore::Slot_Skirt); - apparelChanged = true; - } - if(helmet != inv.getSlot(MWWorld::InventoryStore::Slot_Helmet)){ - apparelChanged = true; - helmet = inv.getSlot(MWWorld::InventoryStore::Slot_Helmet); - removePartGroup(MWWorld::InventoryStore::Slot_Helmet); - - } - if(cuirass != inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass)){ - cuirass = inv.getSlot(MWWorld::InventoryStore::Slot_Cuirass); - removePartGroup(MWWorld::InventoryStore::Slot_Cuirass); - apparelChanged = true; - - } - if(greaves != inv.getSlot(MWWorld::InventoryStore::Slot_Greaves)){ - greaves = inv.getSlot(MWWorld::InventoryStore::Slot_Greaves); - removePartGroup(MWWorld::InventoryStore::Slot_Greaves); - apparelChanged = true; - } - if(leftpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron)){ - leftpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_LeftPauldron); - removePartGroup(MWWorld::InventoryStore::Slot_LeftPauldron); - apparelChanged = true; - - } - if(rightpauldron != inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron)){ - rightpauldron = inv.getSlot(MWWorld::InventoryStore::Slot_RightPauldron); - removePartGroup(MWWorld::InventoryStore::Slot_RightPauldron); - apparelChanged = true; - - } - if(!isBeast && boots != inv.getSlot(MWWorld::InventoryStore::Slot_Boots)){ - boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots); - removePartGroup(MWWorld::InventoryStore::Slot_Boots); - apparelChanged = true; - - } - if(leftglove != inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet)){ - leftglove = inv.getSlot(MWWorld::InventoryStore::Slot_LeftGauntlet); - removePartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet); - apparelChanged = true; - - } - if(rightglove != inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet)){ - rightglove = inv.getSlot(MWWorld::InventoryStore::Slot_RightGauntlet); - removePartGroup(MWWorld::InventoryStore::Slot_RightGauntlet); - apparelChanged = true; - - } - if(shirt != inv.getSlot(MWWorld::InventoryStore::Slot_Shirt)){ - shirt = inv.getSlot(MWWorld::InventoryStore::Slot_Shirt); - removePartGroup(MWWorld::InventoryStore::Slot_Shirt); - apparelChanged = true; - - } - if(pants != inv.getSlot(MWWorld::InventoryStore::Slot_Pants)){ - pants = inv.getSlot(MWWorld::InventoryStore::Slot_Pants); - removePartGroup(MWWorld::InventoryStore::Slot_Pants); - apparelChanged = true; - - } - - if(apparelChanged){ - - if(robe != inv.end()) - { - MWWorld::Ptr ptr = *robe; - - const ESM::Clothing *clothes = (ptr.get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); - reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); - reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); - } - if(skirtiter != inv.end()) - { - MWWorld::Ptr ptr = *skirtiter; - - const ESM::Clothing *clothes = (ptr.get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts); - reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4); - reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Skirt, 4); - reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); - } - - if(helmet != inv.end()){ - removeIndividualPart(ESM::PRT_Hair); - const ESM::Armor *armor = (helmet->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); - - } - if(cuirass != inv.end()){ - const ESM::Armor *armor = (cuirass->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); - - } - if(greaves != inv.end()){ - const ESM::Armor *armor = (greaves->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); - - } - - if(leftpauldron != inv.end()){ - const ESM::Armor *armor = (leftpauldron->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); - - } - if(rightpauldron != inv.end()){ - const ESM::Armor *armor = (rightpauldron->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); - - } - if(!isBeast && boots != inv.end()){ - if(boots->getTypeName() == typeid(ESM::Clothing).name()){ - const ESM::Clothing *clothes = (boots->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); - } - else if(boots->getTypeName() == typeid(ESM::Armor).name()) - { - const ESM::Armor *armor = (boots->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); - } - - } - if(leftglove != inv.end()){ - if(leftglove->getTypeName() == typeid(ESM::Clothing).name()){ - const ESM::Clothing *clothes = (leftglove->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (leftglove->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); - } - - } - if(rightglove != inv.end()){ - if(rightglove->getTypeName() == typeid(ESM::Clothing).name()){ - const ESM::Clothing *clothes = (rightglove->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); - } - else - { - const ESM::Armor *armor = (rightglove->get())->base; - std::vector parts = armor->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); - } - - } - - if(shirt != inv.end()){ - const ESM::Clothing *clothes = (shirt->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); - } - if(pants != inv.end()){ - const ESM::Clothing *clothes = (pants->get())->base; - std::vector parts = clothes->parts.parts; - addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); - } - } - - if(partpriorities[ESM::PRT_Head] < 1){ - addOrReplaceIndividualPart(ESM::PRT_Head, -1,1,headModel); - } - if(partpriorities[ESM::PRT_Hair] < 1 && partpriorities[ESM::PRT_Head] <= 1){ - addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1,hairModel); - } - if(partpriorities[ESM::PRT_Neck] < 1){ - const ESM::BodyPart *neckPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "neck"); - if(neckPart) - addOrReplaceIndividualPart(ESM::PRT_Neck, -1,1,"meshes\\" + neckPart->model); - } - if(partpriorities[ESM::PRT_Cuirass] < 1){ - const ESM::BodyPart *chestPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "chest"); - if(chestPart) - addOrReplaceIndividualPart(ESM::PRT_Cuirass, -1,1,"meshes\\" + chestPart->model); - } - - if(partpriorities[ESM::PRT_Groin] < 1){ - const ESM::BodyPart *groinPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "groin"); - if(groinPart) - addOrReplaceIndividualPart(ESM::PRT_Groin, -1,1,"meshes\\" + groinPart->model); - } - if(partpriorities[ESM::PRT_RHand] < 1){ - const ESM::BodyPart *handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hand"); - if(!handPart) - handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hands"); - if(handPart) - addOrReplaceIndividualPart(ESM::PRT_RHand, -1,1,"meshes\\" + handPart->model); - } - if(partpriorities[ESM::PRT_LHand] < 1){ - const ESM::BodyPart *handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hand"); - if(!handPart) - handPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "hands"); - if(handPart) - addOrReplaceIndividualPart(ESM::PRT_LHand, -1,1,"meshes\\" + handPart->model); - } - - if(partpriorities[ESM::PRT_RWrist] < 1){ - const ESM::BodyPart *wristPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "wrist"); - if(wristPart) - addOrReplaceIndividualPart(ESM::PRT_RWrist, -1,1,"meshes\\" + wristPart->model); - } - if(partpriorities[ESM::PRT_LWrist] < 1){ - const ESM::BodyPart *wristPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "wrist"); - if(wristPart) - addOrReplaceIndividualPart(ESM::PRT_LWrist, -1,1,"meshes\\" + wristPart->model); - } - if(partpriorities[ESM::PRT_RForearm] < 1){ - const ESM::BodyPart *forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "forearm"); - if(bodyRaceID == "b_n_argonian_f_") - forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search ("b_n_argonian_m_forearm"); - if(forearmPart) - addOrReplaceIndividualPart(ESM::PRT_RForearm, -1,1,"meshes\\" + forearmPart->model); - } - if(partpriorities[ESM::PRT_LForearm] < 1){ - const ESM::BodyPart *forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "forearm"); - if(bodyRaceID == "b_n_argonian_f_") - forearmPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search ("b_n_argonian_m_forearm"); - if(forearmPart) - addOrReplaceIndividualPart(ESM::PRT_LForearm, -1,1,"meshes\\" + forearmPart->model); - } - if(partpriorities[ESM::PRT_RUpperarm] < 1){ - const ESM::BodyPart *armPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper arm"); - if(armPart) - addOrReplaceIndividualPart(ESM::PRT_RUpperarm, -1,1,"meshes\\" + armPart->model); - } - if(partpriorities[ESM::PRT_LUpperarm] < 1){ - const ESM::BodyPart *armPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper arm"); - if(armPart) - addOrReplaceIndividualPart(ESM::PRT_LUpperarm, -1,1,"meshes\\" + armPart->model); - } - if(partpriorities[ESM::PRT_RFoot] < 1){ - const ESM::BodyPart *footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "foot"); - if(isBeast && !footPart) - footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "feet"); - if(footPart) - addOrReplaceIndividualPart(ESM::PRT_RFoot, -1,1,"meshes\\" + footPart->model); - } - if(partpriorities[ESM::PRT_LFoot] < 1){ - const ESM::BodyPart *footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "foot"); - if(isBeast && !footPart) - footPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "feet"); - if(footPart) - addOrReplaceIndividualPart(ESM::PRT_LFoot, -1,1,"meshes\\" + footPart->model); - } - if(partpriorities[ESM::PRT_RAnkle] < 1){ - const ESM::BodyPart *anklePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "ankle"); - if(anklePart) - addOrReplaceIndividualPart(ESM::PRT_RAnkle, -1,1,"meshes\\" + anklePart->model); - } - if(partpriorities[ESM::PRT_LAnkle] < 1){ - const ESM::BodyPart *anklePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "ankle"); - if(anklePart) - addOrReplaceIndividualPart(ESM::PRT_LAnkle, -1,1,"meshes\\" + anklePart->model); - } - if(partpriorities[ESM::PRT_RKnee] < 1){ - const ESM::BodyPart *kneePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "knee"); - if(kneePart) - addOrReplaceIndividualPart(ESM::PRT_RKnee, -1,1,"meshes\\" + kneePart->model); - } - if(partpriorities[ESM::PRT_LKnee] < 1){ - const ESM::BodyPart *kneePart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "knee"); - if(kneePart) - addOrReplaceIndividualPart(ESM::PRT_LKnee, -1,1,"meshes\\" + kneePart->model); - } - if(partpriorities[ESM::PRT_RLeg] < 1){ - const ESM::BodyPart *legPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper leg"); - if(legPart) - addOrReplaceIndividualPart(ESM::PRT_RLeg, -1,1,"meshes\\" + legPart->model); - } - if(partpriorities[ESM::PRT_LLeg] < 1){ - const ESM::BodyPart *legPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "upper leg"); - if(legPart) - addOrReplaceIndividualPart(ESM::PRT_LLeg, -1,1,"meshes\\" + legPart->model); - } - if(partpriorities[ESM::PRT_Tail] < 1){ - const ESM::BodyPart *tailPart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (bodyRaceID + "tail"); - if(tailPart) - addOrReplaceIndividualPart(ESM::PRT_Tail, -1,1,"meshes\\" + tailPart->model); - } - - - - - - - - -} - -Ogre::Entity* NpcAnimation::insertBoundedPart(const std::string &mesh, std::string bonename){ - - NIFLoader::load(mesh); - Ogre::Entity* part = mRend.getScene()->createEntity(mesh); - part->setVisibilityFlags(RV_Actors); - - base->attachObjectToBone(bonename, part); - return part; -} -void NpcAnimation::insertFootPart(int type, const std::string &mesh){ - std::string meshAndSuffix = mesh; - if(type == ESM::PRT_LFoot) - meshAndSuffix += "*|"; - NIFLoader::load(meshAndSuffix); - Ogre::Entity* part = mRend.getScene()->createEntity(meshAndSuffix); - std::vector* shape = ((NIFLoader::getSingletonPtr())->getShapes(meshAndSuffix)); - if(shape == 0){ - if(type == ESM::PRT_LFoot){ - base->attachObjectToBone("Left Foot", part); - lfoot = part; - } - else if (type == ESM::PRT_RFoot){ - base->attachObjectToBone("Right Foot", part); - rfoot = part; - } - } - else{ - if(type == ESM::PRT_LFoot) - lFreeFoot = insertFreePart(mesh, "::"); - else if (type == ESM::PRT_RFoot) - rFreeFoot = insertFreePart(mesh, ":<"); - } - - - -} -std::pair*> NpcAnimation::insertFreePart(const std::string &mesh, const std::string& suffix){ - - std::string meshNumbered = mesh + getUniqueID(mesh + suffix) + suffix; - NIFLoader::load(meshNumbered); - - Ogre::Entity* part = mRend.getScene()->createEntity(meshNumbered); - part->setVisibilityFlags(RV_Actors); - - insert->attachObject(part); - - std::vector* shape = ((NIFLoader::getSingletonPtr())->getShapes(mesh + "0000" + suffix)); - if(shape){ - handleShapes(shape, part, base->getSkeleton()); - } - std::pair*> pair = std::make_pair(part, shape); - return pair; -} - - - - -void NpcAnimation::runAnimation(float timepassed){ - - if(timeToChange > .2){ - - timeToChange = 0; - - updateParts(); - } - - timeToChange += timepassed; - - //1. Add the amount of time passed to time - - //2. Handle the animation transforms dependent on time - - //3. Handle the shapes dependent on animation transforms - if(animate > 0){ - time += timepassed; - - if(time > stopTime){ - animate--; - - if(animate == 0) - time = stopTime; - else - time = startTime + (time - stopTime); - } - - handleAnimationTransforms(); - - - vecRotPos.clear(); - - - if(lFreeFoot.first) - handleShapes(lFreeFoot.second, lFreeFoot.first, base->getSkeleton()); - if(rFreeFoot.first) - handleShapes(rFreeFoot.second, rFreeFoot.first, base->getSkeleton()); - - if(chest.first) - handleShapes(chest.second, chest.first, base->getSkeleton()); - if(tail.first) - handleShapes(tail.second, tail.first, base->getSkeleton()); - if(skirt.first){ - handleShapes(skirt.second, skirt.first, base->getSkeleton()); - } - if(lhand.first) - handleShapes(lhand.second, lhand.first, base->getSkeleton()); - if(rhand.first) - handleShapes(rhand.second, rhand.first, base->getSkeleton()); - -} -} - -void NpcAnimation::removeIndividualPart(int type){ - partpriorities[type] = 0; - partslots[type] = -1; - - if(type == ESM::PRT_Head && head){ //0 - base->detachObjectFromBone(head); - head = 0; - } - else if(type == ESM::PRT_Hair && hair){//1 - base->detachObjectFromBone(hair); - hair = 0; - } - else if(type == ESM::PRT_Neck && neck){//2 - base->detachObjectFromBone(neck); - neck = 0; - } - else if(type == ESM::PRT_Cuirass && chest.first){//3 - insert->detachObject(chest.first); - chest = zero; - } - else if(type == ESM::PRT_Groin && groin){//4 - base->detachObjectFromBone(groin); - groin = 0; - } - else if(type == ESM::PRT_Skirt && skirt.first){//5 - insert->detachObject(skirt.first); - skirt = zero; - } - else if(type == ESM::PRT_RHand && rhand.first){//6 - insert->detachObject(rhand.first); - rhand = zero; - } - else if(type == ESM::PRT_LHand && lhand.first){//7 - insert->detachObject(lhand.first); - lhand = zero; - } - else if(type == ESM::PRT_RWrist && rWrist){//8 - base->detachObjectFromBone(rWrist); - rWrist = 0; - } - else if(type == ESM::PRT_LWrist && lWrist){//9 - base->detachObjectFromBone(lWrist); - lWrist = 0; - } - else if(type == ESM::PRT_Shield){//10 - - } - else if(type == ESM::PRT_RForearm && rForearm){//11 - base->detachObjectFromBone(rForearm); - rForearm = 0; - } - else if(type == ESM::PRT_LForearm && lForearm){//12 - base->detachObjectFromBone(lForearm); - lForearm = 0; - } - else if(type == ESM::PRT_RUpperarm && rupperArm){//13 - base->detachObjectFromBone(rupperArm); - rupperArm = 0; - } - else if(type == ESM::PRT_LUpperarm && lupperArm){//14 - base->detachObjectFromBone(lupperArm); - lupperArm = 0; - } - else if(type == ESM::PRT_RFoot){ //15 - if(rfoot){ - base->detachObjectFromBone(rfoot); - rfoot = 0; - } - else if(rFreeFoot.first){ - insert->detachObject(rFreeFoot.first); - rFreeFoot = zero; - } - } - else if(type == ESM::PRT_LFoot){ //16 - if(lfoot){ - base->detachObjectFromBone(lfoot); - lfoot = 0; - } - else if(lFreeFoot.first){ - insert->detachObject(lFreeFoot.first); - lFreeFoot = zero; - } - } - else if(type == ESM::PRT_RAnkle && rAnkle){ //17 - base->detachObjectFromBone(rAnkle); - rAnkle = 0; - } - else if(type == ESM::PRT_LAnkle && lAnkle){ //18 - base->detachObjectFromBone(lAnkle); - lAnkle = 0; - } - else if(type == ESM::PRT_RKnee && rKnee){ //19 - base->detachObjectFromBone(rKnee); - rKnee = 0; - } - else if(type == ESM::PRT_LKnee && lKnee){ //20 - base->detachObjectFromBone(lKnee); - lKnee = 0; - } - else if(type == ESM::PRT_RLeg && rUpperLeg){ //21 - base->detachObjectFromBone(rUpperLeg); - rUpperLeg = 0; - } - else if(type == ESM::PRT_LLeg && lUpperLeg){ //22 - base->detachObjectFromBone(lUpperLeg); - lUpperLeg = 0; - } - else if(type == ESM::PRT_RPauldron && rclavicle){ //23 - base->detachObjectFromBone(rclavicle); - rclavicle = 0; - } - else if(type == ESM::PRT_LPauldron && lclavicle){ //24 - base->detachObjectFromBone(lclavicle); - lclavicle = 0; - } - else if(type == ESM::PRT_Weapon){ //25 - - } - else if(type == ESM::PRT_Tail && tail.first){ //26 - insert->detachObject(tail.first); - tail = zero; - } - - - - - } - - void NpcAnimation::reserveIndividualPart(int type, int group, int priority){ - if(priority > partpriorities[type]){ - removeIndividualPart(type); - partpriorities[type] = priority; - partslots[type] = group; - } - } - - void NpcAnimation::removePartGroup(int group){ - for(int i = 0; i < 27; i++){ - if(partslots[i] == group){ - removeIndividualPart(i); - } - } - } - bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh){ - if(priority > partpriorities[type]){ - removeIndividualPart(type); - partslots[type] = group; - partpriorities[type] = priority; - switch(type){ - case ESM::PRT_Head: //0 - head = insertBoundedPart(mesh, "Head"); - break; - case ESM::PRT_Hair: //1 - hair = insertBoundedPart(mesh, "Head"); - break; - case ESM::PRT_Neck: //2 - neck = insertBoundedPart(mesh, "Neck"); - break; - case ESM::PRT_Cuirass: //3 - chest = insertFreePart(mesh, ":\""); - break; - case ESM::PRT_Groin: //4 - groin = insertBoundedPart(mesh, "Groin"); - break; - case ESM::PRT_Skirt: //5 - skirt = insertFreePart(mesh, ":|"); - break; - case ESM::PRT_RHand: //6 - rhand = insertFreePart(mesh, ":?"); - break; - case ESM::PRT_LHand: //7 - lhand = insertFreePart(mesh, ":>"); - break; - case ESM::PRT_RWrist: //8 - rWrist = insertBoundedPart(mesh, "Right Wrist"); - break; - case ESM::PRT_LWrist: //9 - lWrist = insertBoundedPart(mesh + "*|", "Left Wrist"); - break; - case ESM::PRT_Shield: //10 - break; - case ESM::PRT_RForearm: //11 - rForearm = insertBoundedPart(mesh, "Right Forearm"); - break; - case ESM::PRT_LForearm: //12 - lForearm = insertBoundedPart(mesh + "*|", "Left Forearm"); - break; - case ESM::PRT_RUpperarm: //13 - rupperArm = insertBoundedPart(mesh, "Right Upper Arm"); - break; - case ESM::PRT_LUpperarm: //14 - lupperArm = insertBoundedPart(mesh + "*|", "Left Upper Arm"); - break; - case ESM::PRT_RFoot: //15 - insertFootPart(type, mesh); - break; - case ESM::PRT_LFoot: //16 - insertFootPart(type, mesh); - break; - case ESM::PRT_RAnkle: //17 - rAnkle = insertBoundedPart(mesh , "Right Ankle"); - break; - case ESM::PRT_LAnkle: //18 - lAnkle = insertBoundedPart(mesh + "*|", "Left Ankle"); - break; - case ESM::PRT_RKnee: //19 - rKnee = insertBoundedPart(mesh , "Right Knee"); - break; - case ESM::PRT_LKnee: //20 - lKnee = insertBoundedPart(mesh + "*|", "Left Knee"); - break; - case ESM::PRT_RLeg: //21 - rUpperLeg = insertBoundedPart(mesh, "Right Upper Leg"); - break; - case ESM::PRT_LLeg: //22 - lUpperLeg = insertBoundedPart(mesh + "*|", "Left Upper Leg"); - break; - case ESM::PRT_RPauldron: //23 - rclavicle = insertBoundedPart(mesh , "Right Clavicle"); - break; - case ESM::PRT_LPauldron: //24 - lclavicle = insertBoundedPart(mesh + "*|", "Left Clavicle"); - break; - case ESM::PRT_Weapon: //25 - break; - case ESM::PRT_Tail: //26 - tail = insertFreePart(mesh, ":*"); - break; - - - } - return true; - } - return false; - } - - void NpcAnimation::addPartGroup(int group, int priority, std::vector& parts){ - for(std::size_t i = 0; i < parts.size(); i++) + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) { - ESM::PartReference part = parts[i]; - - const ESM::BodyPart *bodypart = 0; - - if(isFemale) - bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (part.female); - if(!bodypart) - bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search (part.male); - if(bodypart){ - addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); - } - else - reserveIndividualPart(part.part, group, priority); - + Ogre::Pass* pass = passIt.getNext(); + if (pass->getDepthWriteEnabled() == false) + transparent = true; } + } + } + base->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + } + + if(mEntityList.mSkelBase) + { + Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator as = aset->getAnimationStateIterator(); + while(as.hasMoreElements()) + { + Ogre::AnimationState *state = as.getNext(); + state->setEnabled(true); + state->setLoop(false); + } + } + + if(isFemale) + mInsert->scale(race->data.height.female, race->data.height.female, race->data.height.female); + else + mInsert->scale(race->data.height.male, race->data.height.male, race->data.height.male); + updateParts(); +} + +void NpcAnimation::updateParts() +{ + bool apparelChanged = false; + + const struct { + MWWorld::ContainerStoreIterator *iter; + int slot; + } slotlist[] = { + { &robe, MWWorld::InventoryStore::Slot_Robe }, + { &skirtiter, MWWorld::InventoryStore::Slot_Skirt }, + { &helmet, MWWorld::InventoryStore::Slot_Helmet }, + { &cuirass, MWWorld::InventoryStore::Slot_Cuirass }, + { &greaves, MWWorld::InventoryStore::Slot_Greaves }, + { &leftpauldron, MWWorld::InventoryStore::Slot_LeftPauldron }, + { &rightpauldron, MWWorld::InventoryStore::Slot_RightPauldron }, + { &boots, MWWorld::InventoryStore::Slot_Boots }, + { &leftglove, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { &rightglove, MWWorld::InventoryStore::Slot_RightGauntlet }, + { &shirt, MWWorld::InventoryStore::Slot_Shirt }, + { &pants, MWWorld::InventoryStore::Slot_Pants }, + }; + for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) + { + MWWorld::ContainerStoreIterator iter = mInv.getSlot(slotlist[i].slot); + if(*slotlist[i].iter != iter) + { + *slotlist[i].iter = iter; + removePartGroup(slotlist[i].slot); + apparelChanged = true; + } + } + + if(apparelChanged) + { + if(robe != mInv.end()) + { + MWWorld::Ptr ptr = *robe; + + const ESM::Clothing *clothes = (ptr.get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Robe, 5, parts); + reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_Skirt, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LUpperarm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RKnee, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LKnee, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RForearm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LForearm, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); + reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); + } + if(skirtiter != mInv.end()) + { + MWWorld::Ptr ptr = *skirtiter; + + const ESM::Clothing *clothes = (ptr.get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Skirt, 4, parts); + reserveIndividualPart(ESM::PRT_Groin, MWWorld::InventoryStore::Slot_Skirt, 4); + reserveIndividualPart(ESM::PRT_RLeg, MWWorld::InventoryStore::Slot_Skirt, 4); + reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); + } + + if(helmet != mInv.end()) + { + removeIndividualPart(ESM::PRT_Hair); + const ESM::Armor *armor = (helmet->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); + } + if(cuirass != mInv.end()) + { + const ESM::Armor *armor = (cuirass->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); + } + if(greaves != mInv.end()) + { + const ESM::Armor *armor = (greaves->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); + } + + if(leftpauldron != mInv.end()) + { + const ESM::Armor *armor = (leftpauldron->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); + } + if(rightpauldron != mInv.end()) + { + const ESM::Armor *armor = (rightpauldron->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); + } + if(boots != mInv.end()) + { + if(boots->getTypeName() == typeid(ESM::Clothing).name()) + { + const ESM::Clothing *clothes = (boots->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); + } + else if(boots->getTypeName() == typeid(ESM::Armor).name()) + { + const ESM::Armor *armor = (boots->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); + } + } + if(leftglove != mInv.end()) + { + if(leftglove->getTypeName() == typeid(ESM::Clothing).name()) + { + const ESM::Clothing *clothes = (leftglove->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); + } + else + { + const ESM::Armor *armor = (leftglove->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); + } + } + if(rightglove != mInv.end()) + { + if(rightglove->getTypeName() == typeid(ESM::Clothing).name()) + { + const ESM::Clothing *clothes = (rightglove->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); + } + else + { + const ESM::Armor *armor = (rightglove->get())->base; + std::vector parts = armor->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); + } + + } + + if(shirt != mInv.end()) + { + const ESM::Clothing *clothes = (shirt->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); + } + if(pants != mInv.end()) + { + const ESM::Clothing *clothes = (pants->get())->base; + std::vector parts = clothes->parts.parts; + addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); + } + } + + if(mPartPriorities[ESM::PRT_Head] < 1) + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, headModel); + if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, hairModel); + + static const struct { + ESM::PartReferenceType type; + const char name[2][12]; + } PartTypeList[] = { + { ESM::PRT_Neck, { "neck", "" } }, + { ESM::PRT_Cuirass, { "chest", "" } }, + { ESM::PRT_Groin, { "groin", "" } }, + { ESM::PRT_RHand, { "hand", "hands" } }, + { ESM::PRT_LHand, { "hand", "hands" } }, + { ESM::PRT_RWrist, { "wrist", "" } }, + { ESM::PRT_LWrist, { "wrist", "" } }, + { ESM::PRT_RForearm, { "forearm", "" } }, + { ESM::PRT_LForearm, { "forearm", "" } }, + { ESM::PRT_RUpperarm, { "upper arm", "" } }, + { ESM::PRT_LUpperarm, { "upper arm", "" } }, + { ESM::PRT_RFoot, { "foot", "feet" } }, + { ESM::PRT_LFoot, { "foot", "feet" } }, + { ESM::PRT_RAnkle, { "ankle", "" } }, + { ESM::PRT_LAnkle, { "ankle", "" } }, + { ESM::PRT_RKnee, { "knee", "" } }, + { ESM::PRT_LKnee, { "knee", "" } }, + { ESM::PRT_RLeg, { "upper leg", "" } }, + { ESM::PRT_LLeg, { "upper leg", "" } }, + { ESM::PRT_Tail, { "tail", "" } } + }; + + const ESMS::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) + { + if(mPartPriorities[PartTypeList[i].type] < 1) + { + const ESM::BodyPart *part = NULL; + bool tryfemale = isFemale; + int ni = 0; + do { + part = store.bodyParts.search(bodyRaceID+(tryfemale?"_f_":"_m_")+PartTypeList[i].name[ni]); + if(part) break; + + ni ^= 1; + if(ni == 0) + { + if(!tryfemale) + break; + tryfemale = false; + } + } while(1); + + if(part) + addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->model); + } } } + +NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, const std::string &bonename) +{ + NifOgre::EntityList entities = NIFLoader::createEntities(mEntityList.mSkelBase, bonename, + mInsert, mesh); + std::vector &parts = entities.mEntities; + for(size_t i = 0;i < parts.size();i++) + parts[i]->setVisibilityFlags(RV_Actors); + return entities; +} + +void NpcAnimation::runAnimation(float timepassed) +{ + if(timeToChange > .2) + { + timeToChange = 0; + updateParts(); + } + timeToChange += timepassed; + + Animation::runAnimation(timepassed); +} + +void NpcAnimation::removeEntities(NifOgre::EntityList &entities) +{ + assert(&entities != &mEntityList); + + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < entities.mEntities.size();i++) + { + entities.mEntities[i]->detachFromParent(); + sceneMgr->destroyEntity(entities.mEntities[i]); + } + entities.mEntities.clear(); + entities.mSkelBase = NULL; +} + +void NpcAnimation::removeIndividualPart(int type) +{ + mPartPriorities[type] = 0; + mPartslots[type] = -1; + + if(type == ESM::PRT_Head) //0 + removeEntities(head); + else if(type == ESM::PRT_Hair) //1 + removeEntities(hair); + else if(type == ESM::PRT_Neck) //2 + removeEntities(neck); + else if(type == ESM::PRT_Cuirass)//3 + removeEntities(chest); + else if(type == ESM::PRT_Groin)//4 + removeEntities(groin); + else if(type == ESM::PRT_Skirt)//5 + removeEntities(skirt); + else if(type == ESM::PRT_RHand)//6 + removeEntities(rHand); + else if(type == ESM::PRT_LHand)//7 + removeEntities(lHand); + else if(type == ESM::PRT_RWrist)//8 + removeEntities(rWrist); + else if(type == ESM::PRT_LWrist) //9 + removeEntities(lWrist); + else if(type == ESM::PRT_Shield) //10 + { + } + else if(type == ESM::PRT_RForearm) //11 + removeEntities(rForearm); + else if(type == ESM::PRT_LForearm) //12 + removeEntities(lForearm); + else if(type == ESM::PRT_RUpperarm) //13 + removeEntities(rupperArm); + else if(type == ESM::PRT_LUpperarm) //14 + removeEntities(lupperArm); + else if(type == ESM::PRT_RFoot) //15 + removeEntities(rfoot); + else if(type == ESM::PRT_LFoot) //16 + removeEntities(lfoot); + else if(type == ESM::PRT_RAnkle) //17 + removeEntities(rAnkle); + else if(type == ESM::PRT_LAnkle) //18 + removeEntities(lAnkle); + else if(type == ESM::PRT_RKnee) //19 + removeEntities(rKnee); + else if(type == ESM::PRT_LKnee) //20 + removeEntities(lKnee); + else if(type == ESM::PRT_RLeg) //21 + removeEntities(rUpperLeg); + else if(type == ESM::PRT_LLeg) //22 + removeEntities(lUpperLeg); + else if(type == ESM::PRT_RPauldron) //23 + removeEntities(rclavicle); + else if(type == ESM::PRT_LPauldron) //24 + removeEntities(lclavicle); + else if(type == ESM::PRT_Weapon) //25 + { + } + else if(type == ESM::PRT_Tail) //26 + removeEntities(tail); +} + +void NpcAnimation::reserveIndividualPart(int type, int group, int priority) +{ + if(priority > mPartPriorities[type]) + { + removeIndividualPart(type); + mPartPriorities[type] = priority; + mPartslots[type] = group; + } +} + +void NpcAnimation::removePartGroup(int group) +{ + for(int i = 0; i < 27; i++) + { + if(mPartslots[i] == group) + removeIndividualPart(i); + } +} + +bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh) +{ + if(priority <= mPartPriorities[type]) + return false; + + removeIndividualPart(type); + mPartslots[type] = group; + mPartPriorities[type] = priority; + switch(type) + { + case ESM::PRT_Head: //0 + head = insertBoundedPart(mesh, "Head"); + break; + case ESM::PRT_Hair: //1 + hair = insertBoundedPart(mesh, "Head"); + break; + case ESM::PRT_Neck: //2 + neck = insertBoundedPart(mesh, "Neck"); + break; + case ESM::PRT_Cuirass: //3 + chest = insertBoundedPart(mesh, "Chest"); + break; + case ESM::PRT_Groin: //4 + groin = insertBoundedPart(mesh, "Groin"); + break; + case ESM::PRT_Skirt: //5 + skirt = insertBoundedPart(mesh, "Groin"); + break; + case ESM::PRT_RHand: //6 + rHand = insertBoundedPart(mesh, "Right Hand"); + break; + case ESM::PRT_LHand: //7 + lHand = insertBoundedPart(mesh, "Left Hand"); + break; + case ESM::PRT_RWrist: //8 + rWrist = insertBoundedPart(mesh, "Right Wrist"); + break; + case ESM::PRT_LWrist: //9 + lWrist = insertBoundedPart(mesh, "Left Wrist"); + break; + case ESM::PRT_Shield: //10 + break; + case ESM::PRT_RForearm: //11 + rForearm = insertBoundedPart(mesh, "Right Forearm"); + break; + case ESM::PRT_LForearm: //12 + lForearm = insertBoundedPart(mesh, "Left Forearm"); + break; + case ESM::PRT_RUpperarm: //13 + rupperArm = insertBoundedPart(mesh, "Right Upper Arm"); + break; + case ESM::PRT_LUpperarm: //14 + lupperArm = insertBoundedPart(mesh, "Left Upper Arm"); + break; + case ESM::PRT_RFoot: //15 + rfoot = insertBoundedPart(mesh, "Right Foot"); + break; + case ESM::PRT_LFoot: //16 + lfoot = insertBoundedPart(mesh, "Left Foot"); + break; + case ESM::PRT_RAnkle: //17 + rAnkle = insertBoundedPart(mesh, "Right Ankle"); + break; + case ESM::PRT_LAnkle: //18 + lAnkle = insertBoundedPart(mesh, "Left Ankle"); + break; + case ESM::PRT_RKnee: //19 + rKnee = insertBoundedPart(mesh, "Right Knee"); + break; + case ESM::PRT_LKnee: //20 + lKnee = insertBoundedPart(mesh, "Left Knee"); + break; + case ESM::PRT_RLeg: //21 + rUpperLeg = insertBoundedPart(mesh, "Right Upper Leg"); + break; + case ESM::PRT_LLeg: //22 + lUpperLeg = insertBoundedPart(mesh, "Left Upper Leg"); + break; + case ESM::PRT_RPauldron: //23 + rclavicle = insertBoundedPart(mesh , "Right Clavicle"); + break; + case ESM::PRT_LPauldron: //24 + lclavicle = insertBoundedPart(mesh, "Left Clavicle"); + break; + case ESM::PRT_Weapon: //25 + break; + case ESM::PRT_Tail: //26 + tail = insertBoundedPart(mesh, "Tail"); + break; + } + return true; +} + +void NpcAnimation::addPartGroup(int group, int priority, std::vector &parts) +{ + for(std::size_t i = 0; i < parts.size(); i++) + { + ESM::PartReference &part = parts[i]; + + const ESM::BodyPart *bodypart = 0; + if(isFemale) + bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search(part.female); + if(!bodypart) + bodypart = MWBase::Environment::get().getWorld()->getStore().bodyParts.search(part.male); + + if(bodypart) + addOrReplaceIndividualPart(part.part, group,priority,"meshes\\" + bodypart->model); + else + reserveIndividualPart(part.part, group, priority); + } +} + +} diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 8f4f8181d..d4b2a5b9e 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -1,73 +1,58 @@ #ifndef _GAME_RENDER_NPCANIMATION_H #define _GAME_RENDER_NPCANIMATION_H -#include "animation.hpp" -#include -#include -#include -#include -#include -#include -#include "../mwworld/refdata.hpp" -#include "../mwworld/ptr.hpp" +#include "animation.hpp" + #include "components/nifogre/ogre_nif_loader.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwclass/npc.hpp" #include "../mwworld/containerstore.hpp" -#include "components/esm/loadarmo.hpp" namespace MWRender{ class NpcAnimation: public Animation{ private: - MWWorld::InventoryStore& inv; - int mStateID; - //Free Parts - std::pair*> chest; - std::pair*> skirt; - std::pair*> lhand; - std::pair*> rhand; - std::pair*> tail; - std::pair*> lFreeFoot; - std::pair*> rFreeFoot; + MWWorld::InventoryStore& mInv; + int mStateID; - int partslots[27]; //Each part slot is taken by clothing, armor, or is empty - int partpriorities[27]; - std::pair*> zero; + int mPartslots[27]; //Each part slot is taken by clothing, armor, or is empty + int mPartPriorities[27]; + //Bounded Parts + NifOgre::EntityList lclavicle; + NifOgre::EntityList rclavicle; + NifOgre::EntityList rupperArm; + NifOgre::EntityList lupperArm; + NifOgre::EntityList rUpperLeg; + NifOgre::EntityList lUpperLeg; + NifOgre::EntityList lForearm; + NifOgre::EntityList rForearm; + NifOgre::EntityList lWrist; + NifOgre::EntityList rWrist; + NifOgre::EntityList rKnee; + NifOgre::EntityList lKnee; + NifOgre::EntityList neck; + NifOgre::EntityList rAnkle; + NifOgre::EntityList lAnkle; + NifOgre::EntityList groin; + NifOgre::EntityList skirt; + NifOgre::EntityList lfoot; + NifOgre::EntityList rfoot; + NifOgre::EntityList hair; + NifOgre::EntityList rHand; + NifOgre::EntityList lHand; + NifOgre::EntityList head; + NifOgre::EntityList chest; + NifOgre::EntityList tail; - - //Bounded Parts - Ogre::Entity* lclavicle; - Ogre::Entity* rclavicle; - Ogre::Entity* rupperArm; - Ogre::Entity* lupperArm; - Ogre::Entity* rUpperLeg; - Ogre::Entity* lUpperLeg; - Ogre::Entity* lForearm; - Ogre::Entity* rForearm; - Ogre::Entity* lWrist; - Ogre::Entity* rWrist; - Ogre::Entity* rKnee; - Ogre::Entity* lKnee; - Ogre::Entity* neck; - Ogre::Entity* rAnkle; - Ogre::Entity* lAnkle; - Ogre::Entity* groin; - Ogre::Entity* lfoot; - Ogre::Entity* rfoot; - Ogre::Entity* hair; - Ogre::Entity* head; - - Ogre::SceneNode* insert; bool isBeast; bool isFemale; - std::string headModel; - std::string hairModel; - std::string npcName; - std::string bodyRaceID; - float timeToChange; - MWWorld::ContainerStoreIterator robe; + std::string headModel; + std::string hairModel; + std::string npcName; + std::string bodyRaceID; + float timeToChange; + MWWorld::ContainerStoreIterator robe; MWWorld::ContainerStoreIterator helmet; MWWorld::ContainerStoreIterator shirt; MWWorld::ContainerStoreIterator cuirass; @@ -80,22 +65,20 @@ private: MWWorld::ContainerStoreIterator rightglove; MWWorld::ContainerStoreIterator skirtiter; - public: - NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); - virtual ~NpcAnimation(); - Ogre::Entity* insertBoundedPart(const std::string &mesh, std::string bonename); - std::pair*> insertFreePart(const std::string &mesh, const std::string& suffix); - void insertFootPart(int type, const std::string &mesh); - virtual void runAnimation(float timepassed); - void updateParts(); +public: + NpcAnimation(const MWWorld::Ptr& ptr, OEngine::Render::OgreRenderer& _rend, MWWorld::InventoryStore& _inv); + virtual ~NpcAnimation(); + NifOgre::EntityList insertBoundedPart(const std::string &mesh, const std::string &bonename); + virtual void runAnimation(float timepassed); + void updateParts(); + void removeEntities(NifOgre::EntityList &entities); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); bool addOrReplaceIndividualPart(int type, int group, int priority, const std::string &mesh); - void removePartGroup(int group); + void removePartGroup(int group); void addPartGroup(int group, int priority, std::vector& parts); - - }; + } #endif diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index b9efcd3f5..a76ef09d1 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -1,9 +1,18 @@ #include "objects.hpp" #include +#include +#include +#include +#include +#include #include #include + +#include "../mwworld/ptr.hpp" +#include "../mwworld/class.hpp" + #include "renderconst.hpp" using namespace MWRender; @@ -56,7 +65,7 @@ void Objects::insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_) insert->setPosition(f[0], f[1], f[2]); insert->setScale(ptr.getCellRef().scale, ptr.getCellRef().scale, ptr.getCellRef().scale); - + // Convert MW rotation to a quaternion: f = ptr.getCellRef().pos.rot; @@ -84,11 +93,16 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); assert(insert); - NifOgre::NIFLoader::load(mesh); - Ogre::Entity *ent = mRenderer.getScene()->createEntity(mesh); - - - Ogre::Vector3 extents = ent->getBoundingBox().getSize(); + Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, NULL, mesh); + for(size_t i = 0;i < entities.mEntities.size();i++) + { + const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); + bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(), + insert->_getDerivedPosition() + tmp.getMaximum()) + ); + } + Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); float size = std::max(std::max(extents.x, extents.y), extents.z); @@ -100,42 +114,41 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) if (mBounds.find(ptr.getCell()) == mBounds.end()) mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; - - Ogre::AxisAlignedBox bounds = ent->getBoundingBox(); - bounds = Ogre::AxisAlignedBox( - insert->_getDerivedPosition() + bounds.getMinimum(), - insert->_getDerivedPosition() + bounds.getMaximum() - ); - - bounds.scale(insert->getScale()); mBounds[ptr.getCell()].merge(bounds); bool transparent = false; - for (unsigned int i=0; igetNumSubEntities(); ++i) + for(size_t i = 0;i < entities.mEntities.size();i++) { - Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); - Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); - while (techIt.hasMoreElements()) + Ogre::Entity *ent = entities.mEntities[i]; + for (unsigned int i=0; igetNumSubEntities(); ++i) { - Ogre::Technique* tech = techIt.getNext(); - Ogre::Technique::PassIterator passIt = tech->getPassIterator(); - while (passIt.hasMoreElements()) + Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); + Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); + while (techIt.hasMoreElements()) { - Ogre::Pass* pass = passIt.getNext(); + Ogre::Technique* tech = techIt.getNext(); + Ogre::Technique::PassIterator passIt = tech->getPassIterator(); + while (passIt.hasMoreElements()) + { + Ogre::Pass* pass = passIt.getNext(); - if (pass->getDepthWriteEnabled() == false) - transparent = true; + if (pass->getDepthWriteEnabled() == false) + transparent = true; + } } } } if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) { - insert->attachObject(ent); + for(size_t i = 0;i < entities.mEntities.size();i++) + { + Ogre::Entity *ent = entities.mEntities[i]; - ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); - ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); - ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); + ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); + ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); + } } else { @@ -175,15 +188,20 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) // - there will be too many batches. sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500)); - sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); - sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); sg->setCastShadows(true); sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); - mRenderer.getScene()->destroyEntity(ent); + for(size_t i = 0;i < entities.mEntities.size();i++) + { + Ogre::Entity *ent = entities.mEntities[i]; + insert->detachObject(ent); + sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); + + mRenderer.getScene()->destroyEntity(ent); + } } } @@ -194,8 +212,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f Ogre::Light *light = mRenderer.getScene()->createLight(); light->setDiffuseColour (r, g, b); - ESMS::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = ptr.get(); LightInfo info; info.name = light->getName(); @@ -307,7 +324,7 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store) mBounds.erase(store); } -void Objects::buildStaticGeometry(ESMS::CellStore& cell) +void Objects::buildStaticGeometry(MWWorld::Ptr::CellStore& cell) { if(mStaticGeometry.find(&cell) != mStaticGeometry.end()) { @@ -443,3 +460,38 @@ void Objects::update(const float dt) it = mLights.erase(it); } } + +void Objects::rebuildStaticGeometry() +{ + for (std::map::iterator it = mStaticGeometry.begin(); it != mStaticGeometry.end(); ++it) + { + it->second->destroy(); + it->second->build(); + } + + for (std::map::iterator it = mStaticGeometrySmall.begin(); it != mStaticGeometrySmall.end(); ++it) + { + it->second->destroy(); + it->second->build(); + } +} + +void +Objects::updateObjectCell(const MWWorld::Ptr &ptr) +{ + Ogre::SceneNode *node; + MWWorld::CellStore *newCell = ptr.getCell(); + + if(mCellSceneNodes.find(newCell) == mCellSceneNodes.end()) { + node = mMwRoot->createChildSceneNode(); + mCellSceneNodes[newCell] = node; + } else { + node = mCellSceneNodes[newCell]; + } + node->addChild(ptr.getRefData().getBaseNode()); + + /// \note Still unaware how to move aabb and static w/o full rebuild, + /// moving static objects may cause problems + insertMesh(ptr, MWWorld::Class::get(ptr).getModel(ptr)); +} + diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 6132879e6..8594e4fe4 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -1,12 +1,15 @@ #ifndef _GAME_RENDER_OBJECTS_H #define _GAME_RENDER_OBJECTS_H +#include + #include -#include - -#include "../mwworld/refdata.hpp" -#include "../mwworld/ptr.hpp" +namespace MWWorld +{ + class Ptr; + class CellStore; +} namespace MWRender{ @@ -47,10 +50,10 @@ struct LightInfo class Objects{ OEngine::Render::OgreRenderer &mRenderer; - std::map mCellSceneNodes; - std::map mStaticGeometry; - std::map mStaticGeometrySmall; - std::map mBounds; + std::map mCellSceneNodes; + std::map mStaticGeometry; + std::map mStaticGeometrySmall; + std::map mBounds; std::vector mLights; Ogre::SceneNode* mMwRoot; bool mIsStatic; @@ -81,15 +84,20 @@ public: void update (const float dt); ///< per-frame update - Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*); + Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*); ///< get a bounding box that encloses all objects in the specified cell bool deleteObject (const MWWorld::Ptr& ptr); ///< \return found? - void removeCell(MWWorld::Ptr::CellStore* store); - void buildStaticGeometry(ESMS::CellStore &cell); + void removeCell(MWWorld::CellStore* store); + void buildStaticGeometry(MWWorld::CellStore &cell); void setMwRoot(Ogre::SceneNode* root); + + void rebuildStaticGeometry(); + + /// Updates containing cell for object rendering data + void updateObjectCell(const MWWorld::Ptr &ptr); }; } #endif diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index d6baac4b5..94a3f71c8 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -1,27 +1,107 @@ - #include "player.hpp" +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/ptr.hpp" +#include "../mwworld/refdata.hpp" + namespace MWRender { Player::Player (Ogre::Camera *camera, Ogre::SceneNode* node) - : mCamera (camera), mNode (node) + : mCamera (camera), + mNode (node), + mFirstPersonView(true), + mVanityModeEnabled(false) {} - void Player::setRot(float x, float y, float z) + bool Player::setRotation(const Ogre::Vector3 &rot) { - Ogre::SceneNode *sceneNode = mNode; - Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); - Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); + Ogre::SceneNode *sceneNode = mNode; + Ogre::Node* yawNode = sceneNode->getChildIterator().getNext(); + Ogre::Node* pitchNode = yawNode->getChildIterator().getNext(); - // we are only interested in X and Y rotation + // we are only interested in X and Y rotation - // Rotate around X axis - Ogre::Quaternion xr(Ogre::Radian(x), Ogre::Vector3::UNIT_X); + // Rotate around X axis + Ogre::Radian radx(rot.x); + if (radx.valueDegrees() > 89.5f) { + radx = Ogre::Degree(89.5f); + } else if (radx.valueDegrees() < -89.5f) { + radx = Ogre::Degree(-89.5f); + } + Ogre::Quaternion xr(radx, Ogre::Vector3::UNIT_X); - // Rotate around Y axis - Ogre::Quaternion yr(Ogre::Radian(-z), Ogre::Vector3::UNIT_Y); + // Rotate around Y axis + Ogre::Quaternion yr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Y); - pitchNode->setOrientation(xr); - yawNode->setOrientation(yr); + pitchNode->setOrientation(xr); + yawNode->setOrientation(yr); + + updateListener(); + + return !mVanityModeEnabled; + } + + std::string Player::getHandle() const + { + return mNode->getName(); + } + + void Player::attachTo(const MWWorld::Ptr &ptr) + { + ptr.getRefData().setBaseNode(mNode); + } + + bool Player::adjustRotation(const Ogre::Vector3 &rot) + { + Ogre::SceneNode *pitchNode = mCamera->getParentSceneNode(); + Ogre::SceneNode *yawNode = pitchNode->getParentSceneNode(); + + float f = controlFlip(Ogre::Radian(rot.x).valueDegrees()); + if (f != 0.0) { + pitchNode->pitch(Ogre::Degree(f)); + } + yawNode->yaw(Ogre::Radian(-rot.z)); + + updateListener(); + + return !mVanityModeEnabled; + } + + float Player::controlFlip(float shift) + { + Ogre::SceneNode *pitchNode = mCamera->getParentSceneNode(); + Ogre::Quaternion orient = pitchNode->getOrientation(); + + float pitchAngle = + (2 * Ogre::Degree(Ogre::Math::ASin(orient.x)).valueDegrees()); + + if (pitchAngle + shift < 89.5f && pitchAngle + shift > -89.5f) { + return shift; + } + if (pitchAngle > 0) { + float f = 89.5f - pitchAngle - shift; + return (f > 0.f) ? f : 0.f; + } else if (pitchAngle < 0) { + float f = -89.5 - pitchAngle - shift; + return (f < 0.f) ? f : 0.f; + } + return 0.f; + } + + void Player::updateListener() + { + Ogre::Vector3 pos = mCamera->getRealPosition(); + Ogre::Vector3 dir = mCamera->getRealDirection(); + + Ogre::Real xch; + xch = pos.y, pos.y = -pos.z, pos.z = xch; + xch = dir.y, dir.y = -dir.z, dir.z = xch; + + MWBase::Environment::get().getSoundManager()->setListenerPosDir(pos, dir); } } diff --git a/apps/openmw/mwrender/player.hpp b/apps/openmw/mwrender/player.hpp index 406bedb0a..981ecfe0b 100644 --- a/apps/openmw/mwrender/player.hpp +++ b/apps/openmw/mwrender/player.hpp @@ -1,12 +1,19 @@ #ifndef GAME_MWRENDER_PLAYER_H #define GAME_MWRENDER_PLAYER_H -#include -#include +#include + namespace Ogre -{ +{ + class Vector3; class Camera; + class SceneNode; +} + +namespace MWWorld +{ + class Ptr; } namespace MWRender @@ -17,17 +24,41 @@ namespace MWRender Ogre::Camera *mCamera; Ogre::SceneNode* mNode; - public: + bool mFirstPersonView; + bool mVanityModeEnabled; - Player (Ogre::Camera *camera, Ogre::SceneNode* mNode); + float controlFlip(float shift = 0.f); - Ogre::Camera *getCamera() { return mCamera; } + /// Updates sound manager listener data + void updateListener(); - /// Set where the player is looking at. Uses Morrowind (euler) angles - void setRot(float x, float y, float z); + public: - std::string getHandle() const { return mNode->getName(); } - Ogre::SceneNode* getNode() {return mNode;} + Player (Ogre::Camera *camera, Ogre::SceneNode* mNode); + + /// Set where the player is looking at. Uses Morrowind (euler) angles + /// \param rot Rotation angles in radians + /// \return true if player object needs to bo rotated physically + bool setRotation(const Ogre::Vector3 &rot); + + /// \param rot Rotation angles in radians + /// \return true if player object needs to bo rotated physically + bool adjustRotation(const Ogre::Vector3 &rot); + + std::string getHandle() const; + + /// Attach camera to object + /// \note there is no protection from attaching the same camera to + /// several different objects + void attachTo(const MWWorld::Ptr &); + + void toggleViewMode() { + mFirstPersonView = !mFirstPersonView; + } + + void toggleVanityMode() { + mVanityModeEnabled = !mVanityModeEnabled; + } }; } diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index c4aa093c0..9f57833bb 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -14,14 +14,14 @@ enum RenderQueueGroups RQG_Main = Ogre::RENDER_QUEUE_MAIN, + RQG_Alpha = Ogre::RENDER_QUEUE_MAIN+1, + + RQG_OcclusionQuery = Ogre::RENDER_QUEUE_6, + + RQG_UnderWater = Ogre::RENDER_QUEUE_4, + RQG_Water = Ogre::RENDER_QUEUE_7+1, - RQG_Alpha = Ogre::RENDER_QUEUE_MAIN, - - RQG_UnderWater = Ogre::RENDER_QUEUE_7+1, - - RQG_OcclusionQuery = Ogre::RENDER_QUEUE_8, - // Sky late (sun & sun flare) RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE }; @@ -49,12 +49,12 @@ enum VisibilityFlags RV_Sky = 64, - // Sun glare (not visible in reflection) - RV_Glare = 128, + // not visible in reflection + RV_NoReflection = 128, RV_OcclusionQuery = 256, - RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water /// \todo markers (normally hidden) }; diff --git a/apps/openmw/mwrender/renderinginterface.hpp b/apps/openmw/mwrender/renderinginterface.hpp index 03935bef6..8ae2c0f8f 100644 --- a/apps/openmw/mwrender/renderinginterface.hpp +++ b/apps/openmw/mwrender/renderinginterface.hpp @@ -1,16 +1,17 @@ #ifndef _GAME_RENDERING_INTERFACE_H #define _GAME_RENDERING_INTERFACE_H -namespace MWRender{ - class Objects; - class Actors; - class Player; + +namespace MWRender +{ + class Objects; + class Actors; -class RenderingInterface{ + class RenderingInterface + { public: virtual MWRender::Objects& getObjects() = 0; - virtual MWRender::Player& getPlayer() = 0; virtual MWRender::Actors& getActors() = 0; virtual ~RenderingInterface(){}; }; } -#endif \ No newline at end of file +#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 266362f9b..d0019c6b8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1,30 +1,39 @@ #include "renderingmanager.hpp" -#include +#include -#include "OgreRoot.h" -#include "OgreRenderWindow.h" -#include "OgreSceneManager.h" -#include "OgreViewport.h" -#include "OgreCamera.h" -#include "OgreTextureManager.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include -#include "../mwworld/world.hpp" // these includes can be removed once the static-hack is gone -#include "../mwworld/ptr.hpp" -#include "../mwworld/player.hpp" -#include "../mwbase/environment.hpp" #include +#include #include +#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone +#include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" // FIXME +#include "../mwbase/windowmanager.hpp" // FIXME + +#include "../mwworld/ptr.hpp" +#include "../mwworld/player.hpp" + #include "shadows.hpp" -#include "shaderhelper.hpp" #include "localmap.hpp" #include "water.hpp" #include "compositors.hpp" -#include "../mwgui/window_manager.hpp" // FIXME -#include "../mwinput/inputmanager.hpp" // FIXME - using namespace MWRender; using namespace Ogre; @@ -33,6 +42,17 @@ namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine) :mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0) { + // select best shader mode + bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != 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")) + { + Settings::Manager::setString("shader mode", "General", openGL ? "glsl" : "hlsl"); + } + mRendering.createScene("PlayerCam", Settings::Manager::getFloat("field of view", "General"), 5); mRendering.setWindowEventListener(this); @@ -40,9 +60,21 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mWater = 0; - //The fog type must be set before any terrain objects are created as if the - //fog type is set to FOG_NONE then the initially created terrain won't have any fog - configureFog(1, ColourValue(1,1,1)); + // material system + sh::OgrePlatform* platform = new sh::OgrePlatform("General", (resDir / "materials").string()); + platform->setCacheFolder ("./"); + mFactory = new sh::Factory(platform); + + sh::Language lang; + std::string l = Settings::Manager::getString("shader mode", "General"); + if (l == "glsl") + lang = sh::Language_GLSL; + else if (l == "hlsl") + lang = sh::Language_HLSL; + else + lang = sh::Language_CG; + mFactory->setCurrentLanguage (lang); + mFactory->loadAllFiles(); // Set default mipmap level (NB some APIs ignore this) TextureManager::getSingleton().setDefaultNumMipmaps(Settings::Manager::getInt("num mipmaps", "General")); @@ -61,18 +93,33 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Load resources ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); - // Due to the huge world size of MW, we'll want camera-relative rendering. - // This prevents precision artifacts when moving very far from the origin. - mRendering.getScene()->setCameraRelativeRendering(true); + // causes light flicker in opengl when moving.. + //mRendering.getScene()->setCameraRelativeRendering(true); // disable unsupported effects - const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); + //const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); if (!waterShaderSupported()) Settings::Manager::setBool("shader", "Water", false); - if ( !(caps->isShaderProfileSupported("fp40") || caps->isShaderProfileSupported("ps_4_0")) - || !Settings::Manager::getBool("shaders", "Objects")) + if (!Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("enabled", "Shadows", false); + sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); + + sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); + sh::Factory::getInstance ().setGlobalSetting ("fog", "true"); + sh::Factory::getInstance ().setGlobalSetting ("lighting", "true"); + sh::Factory::getInstance ().setGlobalSetting ("num_lights", Settings::Manager::getString ("num lights", "Objects")); + sh::Factory::getInstance ().setGlobalSetting ("terrain_num_lights", Settings::Manager::getString ("num lights", "Terrain")); + sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); + sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); + + sh::Factory::getInstance ().setSharedParameter ("viewportBackground", sh::makeProperty (new sh::Vector3(0,0,0))); + sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(0.0))); + sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(0))); + sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); + sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); + sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); + applyCompositors(); // Turn the entire scene (represented by the 'root' node) -90 @@ -93,7 +140,6 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const cameraPitchNode->attachObject(mRendering.getCamera()); mShadows = new Shadows(&mRendering); - mShaderHelper = new ShaderHelper(this); mTerrainManager = new TerrainManager(mRendering.getScene(), this); @@ -117,7 +163,6 @@ RenderingManager::~RenderingManager () delete mPlayer; delete mSkyManager; delete mDebugging; - delete mShaderHelper; delete mShadows; delete mTerrainManager; delete mLocalMap; @@ -138,10 +183,6 @@ MWRender::Actors& RenderingManager::getActors(){ return mActors; } -MWRender::Player& RenderingManager::getPlayer(){ - return (*mPlayer); -} - OEngine::Render::Fader* RenderingManager::getFader() { return mRendering.getFader(); @@ -206,11 +247,59 @@ void RenderingManager::moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale){ } -void RenderingManager::rotateObject (const MWWorld::Ptr& ptr, const::Ogre::Quaternion& orientation){ +bool +RenderingManager::rotateObject( + const MWWorld::Ptr &ptr, + Ogre::Vector3 &rot, + bool adjust) +{ + bool isActive = ptr.getRefData().getBaseNode() != 0; + bool isPlayer = isActive && ptr.getRefData().getHandle() == "player"; + bool force = true; + + if (isPlayer) { + if (adjust) { + force = mPlayer->adjustRotation(rot); + } else { + force = mPlayer->setRotation(rot); + } + } + MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z); + + if (adjust) { + /// \note Stored and passed in radians + float *f = ptr.getRefData().getPosition().rot; + rot.x += f[0], rot.y += f[1], rot.z += f[2]; + } + if (!isPlayer && isActive) { + Ogre::Quaternion xr(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr(Ogre::Radian(rot.y), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr(Ogre::Radian(rot.z), Ogre::Vector3::UNIT_Z); + + ptr.getRefData().getBaseNode()->setOrientation(xr * yr * zr); + } + return force; } -void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::Ptr::CellStore *store){ +void +RenderingManager::moveObjectToCell( + const MWWorld::Ptr& ptr, + const Ogre::Vector3& pos, + MWWorld::CellStore *store) +{ + Ogre::SceneNode *child = + mRendering.getScene()->getSceneNode(ptr.getRefData().getHandle()); + + Ogre::SceneNode *parent = child->getParentSceneNode(); + parent->removeChild(child); + + if (MWWorld::Class::get(ptr).isActor()) { + mActors.updateObjectCell(ptr); + } else { + mObjects.updateObjectCell(ptr); + } + child->setPosition(pos); } void RenderingManager::update (float duration){ @@ -228,10 +317,20 @@ void RenderingManager::update (float duration){ mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealOrientation() ); - checkUnderwater(); + if (mWater) { + Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); - mWater->update(); + MWBase::World *world = MWBase::Environment::get().getWorld(); + + mWater->updateUnderwater( + world->isUnderwater( + *world->getPlayer().getPlayer().getCell()->cell, + Ogre::Vector3(cam.x, -cam.z, cam.y)) + ); + mWater->update(duration); + } } + void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ if(store->cell->data.flags & store->cell->HasWater || ((!(store->cell->data.flags & ESM::Cell::Interior)) @@ -298,9 +397,9 @@ void RenderingManager::skySetMoonColour (bool red){ bool RenderingManager::toggleRenderMode(int mode) { - if (mode == MWWorld::World::Render_CollisionDebug || mode == MWWorld::World::Render_Pathgrid) + if (mode == MWBase::World::Render_CollisionDebug || mode == MWBase::World::Render_Pathgrid) return mDebugging->toggleRenderMode(mode); - else if (mode == MWWorld::World::Render_Wireframe) + else if (mode == MWBase::World::Render_Wireframe) { if (mRendering.getCamera()->getPolygonMode() == PM_SOLID) { @@ -323,12 +422,15 @@ bool RenderingManager::toggleRenderMode(int mode) } } -void RenderingManager::configureFog(ESMS::CellStore &mCell) +void RenderingManager::configureFog(MWWorld::Ptr::CellStore &mCell) { Ogre::ColourValue color; color.setAsABGR (mCell.cell->ambi.fog); configureFog(mCell.cell->ambi.fogDensity, color); + + if (mWater) + mWater->setViewportBackground (Ogre::ColourValue(0.8f, 0.9f, 1.0f)); } void RenderingManager::configureFog(const float density, const Ogre::ColourValue& colour) @@ -343,11 +445,12 @@ void RenderingManager::configureFog(const float density, const Ogre::ColourValue mRendering.getCamera()->setFarClipDistance ( max / density ); mRendering.getViewport()->setBackgroundColour (colour); - CompositorInstance* inst = CompositorManager::getSingleton().getCompositorChain(mRendering.getViewport())->getCompositor("gbuffer"); - if (inst != 0) - inst->getCompositor()->getTechnique(0)->getTargetPass(0)->getPass(0)->setClearColour(colour); if (mWater) - mWater->setViewportBackground(colour); + mWater->setViewportBackground (colour); + + sh::Factory::getInstance ().setSharedParameter ("viewportBackground", + sh::makeProperty (new sh::Vector3(colour.r, colour.g, colour.b))); + } @@ -372,7 +475,7 @@ void RenderingManager::setAmbientMode() } } -void RenderingManager::configureAmbient(ESMS::CellStore &mCell) +void RenderingManager::configureAmbient(MWWorld::Ptr::CellStore &mCell) { mAmbientColor.setAsABGR (mCell.cell->ambi.ambient); setAmbientMode(); @@ -407,13 +510,6 @@ void RenderingManager::toggleLight() setAmbientMode(); } -void RenderingManager::checkUnderwater() -{ - if(mWater) - { - mWater->checkUnderwater( mRendering.getCamera()->getRealPosition().y ); - } -} void RenderingManager::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) @@ -510,12 +606,14 @@ Shadows* RenderingManager::getShadows() void RenderingManager::switchToInterior() { - mRendering.getScene()->setCameraRelativeRendering(false); + // causes light flicker in opengl when moving.. + //mRendering.getScene()->setCameraRelativeRendering(false); } void RenderingManager::switchToExterior() { - mRendering.getScene()->setCameraRelativeRendering(true); + // causes light flicker in opengl when moving.. + //mRendering.getScene()->setCameraRelativeRendering(true); } Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) @@ -600,7 +698,38 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec else if (it->second == "shader" && it->first == "Water") { applyCompositors(); - mShaderHelper->applyShaders(); + sh::Factory::getInstance ().setGlobalSetting ("mrt_output", useMRT() ? "true" : "false"); + sh::Factory::getInstance ().setGlobalSetting ("simple_water", Settings::Manager::getBool("shader", "Water") ? "false" : "true"); + mObjects.rebuildStaticGeometry (); + } + else if (it->second == "underwater effect" && it->first == "Water") + { + sh::Factory::getInstance ().setGlobalSetting ("underwater_effects", Settings::Manager::getString("underwater effect", "Water")); + mObjects.rebuildStaticGeometry (); + } + else if (it->second == "shaders" && it->first == "Objects") + { + sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); + mObjects.rebuildStaticGeometry (); + } + else if (it->second == "shader mode" && it->first == "General") + { + sh::Language lang; + std::string l = Settings::Manager::getString("shader mode", "General"); + if (l == "glsl") + lang = sh::Language_GLSL; + else if (l == "hlsl") + lang = sh::Language_HLSL; + else + lang = sh::Language_CG; + sh::Factory::getInstance ().setCurrentLanguage (lang); + mObjects.rebuildStaticGeometry (); + } + else if (it->first == "Shadows") + { + mShadows->recreate (); + + mObjects.rebuildStaticGeometry (); } } @@ -647,6 +776,7 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw) void RenderingManager::windowClosed(Ogre::RenderWindow* rw) { + Ogre::Root::getSingleton ().queueEndRendering (); } bool RenderingManager::waterShaderSupported() @@ -664,17 +794,30 @@ void RenderingManager::applyCompositors() { mCompositors->addCompositor("gbuffer", 0); mCompositors->setCompositorEnabled("gbuffer", true); - mCompositors->addCompositor("Underwater", 1); mCompositors->addCompositor("gbufferFinalizer", 2); mCompositors->setCompositorEnabled("gbufferFinalizer", true); } - else - { - mCompositors->addCompositor("UnderwaterNoMRT", 0); - } if (mWater) mWater->assignTextures(); } +void RenderingManager::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) +{ + if (mCompositors->anyCompositorEnabled()) + { + mCompositors->countTrianglesBatches(triangles, batches); + } + else + { + triangles = mRendering.getWindow()->getTriangleCount(); + batches = mRendering.getWindow()->getBatchCount(); + } +} + +void RenderingManager::attachCameraTo(const MWWorld::Ptr &ptr) +{ + mPlayer->attachTo(ptr); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 642c42930..ef6f18a75 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -1,27 +1,14 @@ #ifndef _GAME_RENDERING_MANAGER_H #define _GAME_RENDERING_MANAGER_H - #include "sky.hpp" #include "terrain.hpp" #include "debugging.hpp" -#include "../mwworld/class.hpp" - -#include - -#include -#include #include -#include #include -#include -#include - -#include "../mwworld/ptr.hpp" - #include #include "renderinginterface.hpp" @@ -41,14 +28,18 @@ namespace Ogre namespace MWWorld { - class World; + class Ptr; + class CellStore; +} + +namespace sh +{ + class Factory; } namespace MWRender { - class Shadows; - class ShaderHelper; class LocalMap; class Water; class Compositors; @@ -65,11 +56,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, OEngine::Physic::PhysicEngine* engine); virtual ~RenderingManager(); - - - virtual MWRender::Player& getPlayer(); /// \todo move this to private again as soon as - /// MWWorld::Player has been rewritten to not need access - /// to internal details of the rendering system anymore + void attachCameraTo(const MWWorld::Ptr &ptr); SkyManager* getSkyManager(); Compositors* getCompositors(); @@ -79,18 +66,18 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList OEngine::Render::Fader* getFader(); - void removeCell (MWWorld::Ptr::CellStore *store); + void removeCell (MWWorld::CellStore *store); /// \todo this function should be removed later. Instead the rendering subsystems should track /// when rebatching is needed and update automatically at the end of each frame. - void cellAdded (MWWorld::Ptr::CellStore *store); - void waterAdded(MWWorld::Ptr::CellStore *store); + void cellAdded (MWWorld::CellStore *store); + void waterAdded(MWWorld::CellStore *store); void removeWater(); static const bool useMRT(); - void preCellChange (MWWorld::Ptr::CellStore* store); + void preCellChange (MWWorld::CellStore* store); ///< this event is fired immediately before changing cell void addObject (const MWWorld::Ptr& ptr); @@ -98,14 +85,19 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void moveObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& position); void scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3& scale); - void rotateObject (const MWWorld::Ptr& ptr, const::Ogre::Quaternion& orientation); - void checkUnderwater(); + /// Rotates object accordingly to its type + /// \param rot euler angles in radians + /// \param adjust indicates should rotation be set or adjusted + /// \return true if object needs to be rotated physically + bool rotateObject (const MWWorld::Ptr& ptr, Ogre::Vector3 &rot, bool adjust = false); + void setWaterHeight(const float height); void toggleWater(); + /// Moves object rendering part to proper container /// \param store Cell the object was in previously (\a ptr has already been updated to the new cell). - void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::Ptr::CellStore *store); + void moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Vector3& position, MWWorld::CellStore *store); void update (float duration); @@ -118,14 +110,16 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void disableLights(); void enableLights(); - bool occlusionQuerySupported() { return mOcclusionQuery->supported(); }; - OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; }; + bool occlusionQuerySupported() { return mOcclusionQuery->supported(); } + OcclusionQuery* getOcclusionQuery() { return mOcclusionQuery; } Shadows* getShadows(); void switchToInterior(); void switchToExterior(); + void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); + void setGlare(bool glare); void skyEnable (); void skyDisable (); @@ -134,13 +128,13 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList int skyGetMasserPhase() const; int skyGetSecundaPhase() const; void skySetMoonColour (bool red); - void configureAmbient(ESMS::CellStore &mCell); + void configureAmbient(MWWorld::CellStore &mCell); - void requestMap (MWWorld::Ptr::CellStore* cell); + void requestMap (MWWorld::CellStore* cell); ///< request the local map for a cell /// configure fog according to cell - void configureFog(ESMS::CellStore &mCell); + void configureFog(MWWorld::CellStore &mCell); /// configure fog manually void configureFog(const float density, const Ogre::ColourValue& colour); @@ -173,6 +167,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList private: + sh::Factory* mFactory; + void setAmbientMode(); void setMenuTransparency(float val); @@ -215,8 +211,6 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList MWRender::Shadows* mShadows; - MWRender::ShaderHelper* mShaderHelper; - MWRender::Compositors* mCompositors; }; diff --git a/apps/openmw/mwrender/shaderhelper.cpp b/apps/openmw/mwrender/shaderhelper.cpp deleted file mode 100644 index 59154a295..000000000 --- a/apps/openmw/mwrender/shaderhelper.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include "shaderhelper.hpp" -#include "renderingmanager.hpp" -#include "shadows.hpp" - -#include -#include -#include - -#include - -using namespace Ogre; -using namespace MWRender; - -ShaderHelper::ShaderHelper(RenderingManager* rend) -{ - mRendering = rend; - applyShaders(); -} - -void ShaderHelper::applyShaders() -{ - if (!Settings::Manager::getBool("shaders", "Objects")) return; - - bool mrt = RenderingManager::useMRT(); - bool shadows = Settings::Manager::getBool("enabled", "Shadows"); - bool split = Settings::Manager::getBool("split", "Shadows"); - - // shader for normal rendering - createShader(mrt, shadows, split, "main"); - - // fallback shader without mrt and without shadows - // (useful for reflection and for minimap) - createShader(false, false, false, "main_fallback"); -} - -void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool split, const std::string& name) -{ - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - - const int numsplits = 3; - - // the number of lights to support. - // when rendering an object, OGRE automatically picks the lights that are - // closest to the object being rendered. unfortunately this mechanism does - // not work perfectly for objects batched together (they will all use the same - // lights). to work around this, we are simply pushing the maximum number - // of lights here in order to minimize disappearing lights. - int num_lights = Settings::Manager::getInt("num lights", "Objects"); - - { - // vertex - HighLevelGpuProgramPtr vertex; - if (!mgr.getByName(name+"_vp").isNull()) - mgr.remove(name+"_vp"); - - vertex = mgr.createProgram(name+"_vp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_VERTEX_PROGRAM); - vertex->setParameter("profiles", "vs_4_0 vs_2_x vp40 arbvp1"); - vertex->setParameter("entry_point", "main_vp"); - StringUtil::StrStreamType outStream; - outStream << - "void main_vp( \n" - " float4 position : POSITION, \n" - " float4 normal : NORMAL, \n" - " float4 colour : COLOR, \n" - " in float2 uv : TEXCOORD0, \n" - " out float2 oUV : TEXCOORD0, \n" - " out float4 oPosition : POSITION, \n" - " out float4 oPositionObjSpace : TEXCOORD1, \n" - " out float4 oNormal : TEXCOORD2, \n" - " out float oDepth : TEXCOORD3, \n" - " out float4 oVertexColour : TEXCOORD4, \n"; - if (shadows && !split) outStream << - " out float4 oLightSpacePos0 : TEXCOORD5, \n" - " uniform float4x4 worldMatrix, \n" - " uniform float4x4 texViewProjMatrix0, \n"; - else - { - for (int i=0; isetSource(outStream.str()); - vertex->load(); - vertex->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - if (shadows) - { - vertex->getDefaultParameters()->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX); - if (!split) - vertex->getDefaultParameters()->setNamedAutoConstant("texViewProjMatrix0", GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, 0); - else - { - for (int i=0; igetDefaultParameters()->setNamedAutoConstant("texViewProjMatrix"+StringConverter::toString(i), GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i); - } - } - } - } - - { - // fragment - HighLevelGpuProgramPtr fragment; - if (!mgr.getByName(name+"_fp").isNull()) - mgr.remove(name+"_fp"); - - fragment = mgr.createProgram(name+"_fp", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_FRAGMENT_PROGRAM); - fragment->setParameter("profiles", "ps_4_0 ps_2_x fp40 arbfp1"); - fragment->setParameter("entry_point", "main_fp"); - StringUtil::StrStreamType outStream; - - if (shadows) outStream << - "float depthShadow(sampler2D shadowMap, float4 shadowMapPos, float2 offset) \n" - "{ \n" - " shadowMapPos /= shadowMapPos.w; \n" - " float3 o = float3(offset.xy, -offset.x) * 0.3f; \n" - " float c = (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy - o.xy).r) ? 1 : 0; // top left \n" - " c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy + o.xy).r) ? 1 : 0; // bottom right \n" - " c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy + o.zy).r) ? 1 : 0; // bottom left \n" - " c += (shadowMapPos.z <= tex2D(shadowMap, shadowMapPos.xy - o.zy).r) ? 1 : 0; // top right \n" - " return c / 4; \n" - "} \n"; - - outStream << - "void main_fp( \n" - " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n" - " uniform sampler2D texture : register(s0), \n" - " float4 positionObjSpace : TEXCOORD1, \n" - " float4 normal : TEXCOORD2, \n" - " float iDepth : TEXCOORD3, \n" - " float4 vertexColour : TEXCOORD4, \n" - " uniform float4 fogColour, \n" - " uniform float4 fogParams, \n"; - - if (shadows) outStream << - " uniform float4 shadowFar_fadeStart, \n"; - - if (shadows && !split) outStream << - " uniform sampler2D shadowMap : register(s1), \n" - " float4 lightSpacePos0 : TEXCOORD5, \n" - " uniform float4 invShadowmapSize0, \n"; - else - { - outStream << - " uniform float4 pssmSplitPoints, \n"; - for (int i=0; i shadowFar_fadeStart.x) ? 1 : ((iDepth > shadowFar_fadeStart.y) ? 1-((1-shadow)*fade) : shadow); \n" - " lightColour.xyz += shadow * lit(dot(normalize(lightDir), normalize(normal)), 0, 0).y * lightDiffuse"<setSource(outStream.str()); - fragment->load(); - - for (int i=0; igetDefaultParameters()->setNamedAutoConstant("lightPositionObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i); - fragment->getDefaultParameters()->setNamedAutoConstant("lightDiffuse"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i); - fragment->getDefaultParameters()->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i); - } - fragment->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_SURFACE_AMBIENT_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("lightAmbient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); - fragment->getDefaultParameters()->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS); - - if (shadows) - { - fragment->getDefaultParameters()->setNamedConstant("shadowFar_fadeStart", Vector4(mRendering->getShadows()->getShadowFar(), mRendering->getShadows()->getFadeStart()*mRendering->getShadows()->getShadowFar(), 0, 0)); - for (int i=0; i < (split ? numsplits : 1); ++i) - { - fragment->getDefaultParameters()->setNamedAutoConstant("invShadowmapSize" + StringConverter::toString(i), GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, i+1); - } - if (split) - { - Vector4 splitPoints; - const PSSMShadowCameraSetup::SplitPointList& splitPointList = mRendering->getShadows()->getPSSMSetup()->getSplitPoints(); - // Populate from split point 1, not 0, since split 0 isn't useful (usually 0) - for (int i = 1; i < numsplits; ++i) - { - splitPoints[i-1] = splitPointList[i]; - } - fragment->getDefaultParameters()->setNamedConstant("pssmSplitPoints", splitPoints); - } - } - - if (mrt) - fragment->getDefaultParameters()->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE); - } -} diff --git a/apps/openmw/mwrender/shaderhelper.hpp b/apps/openmw/mwrender/shaderhelper.hpp deleted file mode 100644 index 356d345de..000000000 --- a/apps/openmw/mwrender/shaderhelper.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef GAME_SHADERHELPER_H -#define GAME_SHADERHELPER_H - -#include - -namespace MWRender -{ - class RenderingManager; - - /// - /// \brief manages the main shader - /// - class ShaderHelper - { - public: - ShaderHelper(RenderingManager* rend); - - void applyShaders(); - ///< apply new settings - - private: - RenderingManager* mRendering; - - void createShader(const bool mrt, const bool shadows, const bool split, const std::string& name); - }; - -} - -#endif diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 9a4ae7243..3d9f13243 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "renderconst.hpp" using namespace Ogre; @@ -34,6 +36,9 @@ void Shadows::recreate() bool split = Settings::Manager::getBool("split", "Shadows"); //const bool split = false; + sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false"); + sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false"); + if (!enabled) { mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE); @@ -53,7 +58,7 @@ void Shadows::recreate() mSceneMgr->setShadowTextureSelfShadow(true); mSceneMgr->setShadowCasterRenderBackFaces(true); - mSceneMgr->setShadowTextureCasterMaterial("depth_shadow_caster"); + mSceneMgr->setShadowTextureCasterMaterial("openmw_shadowcaster_default"); mSceneMgr->setShadowTexturePixelFormat(PF_FLOAT32_R); mSceneMgr->setShadowDirectionalLightExtrusionDistance(1000000); @@ -84,18 +89,27 @@ void Shadows::recreate() mSceneMgr->setShadowTextureConfig(i, texsize/4, texsize/4, Ogre::PF_FLOAT32_R);*/ } + // Populate from split point 1, not 0, since split 0 isn't useful (usually 0) + const PSSMShadowCameraSetup::SplitPointList& splitPointList = getPSSMSetup()->getSplitPoints(); + sh::Vector3* splitPoints = new sh::Vector3(splitPointList[1], splitPointList[2], splitPointList[3]); + + sh::Factory::getInstance ().setSharedParameter ("pssmSplitPoints", sh::makeProperty(splitPoints)); + shadowCameraSetup = ShadowCameraSetupPtr(mPSSMSetup); } else { LiSPSMShadowCameraSetup* lispsmSetup = new LiSPSMShadowCameraSetup(); - lispsmSetup->setOptimalAdjustFactor(2); + lispsmSetup->setOptimalAdjustFactor(64); //lispsmSetup->setCameraLightDirectionThreshold(Degree(0)); //lispsmSetup->setUseAggressiveFocusRegion(false); shadowCameraSetup = ShadowCameraSetupPtr(lispsmSetup); } mSceneMgr->setShadowCameraSetup(shadowCameraSetup); + sh::Vector4* shadowFar_fadeStart = new sh::Vector4(mShadowFar, mFadeStart * mShadowFar, 0, 0); + sh::Factory::getInstance ().setSharedParameter ("shadowFar_fadeStart", sh::makeProperty(shadowFar_fadeStart)); + // Set visibility mask for the shadow render textures int visibilityMask = RV_Actors * Settings::Manager::getBool("actor shadows", "Shadows") + (RV_Statics + RV_StaticsSmall) * Settings::Manager::getBool("statics shadows", "Shadows") @@ -111,53 +125,62 @@ void Shadows::recreate() // -------------------------------------------------------------------------------------------------------------------- // --------------------------- Debug overlays to display the content of shadow maps ----------------------------------- // -------------------------------------------------------------------------------------------------------------------- - /* - OverlayManager& mgr = OverlayManager::getSingleton(); - Overlay* overlay; - - // destroy if already exists - if (overlay = mgr.getByName("DebugOverlay")) - mgr.destroy(overlay); - - overlay = mgr.create("DebugOverlay"); - for (size_t i = 0; i < (split ? 3 : 1); ++i) { - TexturePtr tex = mRendering->getScene()->getShadowTexture(i); - - // Set up a debug panel to display the shadow - - if (MaterialManager::getSingleton().resourceExists("Ogre/DebugTexture" + StringConverter::toString(i))) - MaterialManager::getSingleton().remove("Ogre/DebugTexture" + StringConverter::toString(i)); - MaterialPtr debugMat = MaterialManager::getSingleton().create( - "Ogre/DebugTexture" + StringConverter::toString(i), - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - - debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); - TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName()); - t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); + if (Settings::Manager::getBool("debug", "Shadows")) + { + OverlayManager& mgr = OverlayManager::getSingleton(); + Overlay* overlay; - OverlayContainer* debugPanel; - - // destroy container if exists - try - { - if (debugPanel = - static_cast( - mgr.getOverlayElement("Ogre/DebugTexPanel" + StringConverter::toString(i) - ))) - mgr.destroyOverlayElement(debugPanel); - } - catch (Ogre::Exception&) {} - - debugPanel = (OverlayContainer*) - (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugTexPanel" + StringConverter::toString(i))); - debugPanel->_setPosition(0.8, i*0.25); - debugPanel->_setDimensions(0.2, 0.24); - debugPanel->setMaterialName(debugMat->getName()); - debugPanel->show(); - overlay->add2D(debugPanel); - overlay->show(); - } - */ + // destroy if already exists + if ((overlay = mgr.getByName("DebugOverlay"))) + mgr.destroy(overlay); + + overlay = mgr.create("DebugOverlay"); + for (size_t i = 0; i < (split ? 3 : 1); ++i) { + TexturePtr tex = mRendering->getScene()->getShadowTexture(i); + + // Set up a debug panel to display the shadow + + if (MaterialManager::getSingleton().resourceExists("Ogre/DebugTexture" + StringConverter::toString(i))) + MaterialManager::getSingleton().remove("Ogre/DebugTexture" + StringConverter::toString(i)); + MaterialPtr debugMat = MaterialManager::getSingleton().create( + "Ogre/DebugTexture" + StringConverter::toString(i), + ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + + debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); + TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName()); + t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); + + OverlayContainer* debugPanel; + + // destroy container if exists + try + { + if ((debugPanel = + static_cast( + mgr.getOverlayElement("Ogre/DebugTexPanel" + StringConverter::toString(i) + )))) + mgr.destroyOverlayElement(debugPanel); + } + catch (Ogre::Exception&) {} + + debugPanel = (OverlayContainer*) + (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/DebugTexPanel" + StringConverter::toString(i))); + debugPanel->_setPosition(0.8, i*0.25); + debugPanel->_setDimensions(0.2, 0.24); + debugPanel->setMaterialName(debugMat->getName()); + debugPanel->show(); + overlay->add2D(debugPanel); + overlay->show(); + } + } + else + { + OverlayManager& mgr = OverlayManager::getSingleton(); + Overlay* overlay; + + if ((overlay = mgr.getByName("DebugOverlay"))) + mgr.destroy(overlay); + } } PSSMShadowCameraSetup* Shadows::getPSSMSetup() diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 19e45c189..9e551ba2a 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -4,14 +4,26 @@ #include #include #include +#include #include #include #include +#include +#include +#include +#include +#include +#include + +#include #include +#include + #include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" + #include "renderconst.hpp" #include "renderingmanager.hpp" @@ -21,15 +33,51 @@ using namespace Ogre; BillboardObject::BillboardObject( const String& textureName, const float initialSize, const Vector3& position, - SceneNode* rootNode) + SceneNode* rootNode, + const std::string& material) { - init(textureName, initialSize, position, rootNode); + SceneManager* sceneMgr = rootNode->getCreator(); + + Vector3 finalPosition = position.normalisedCopy() * 1000.f; + + static unsigned int bodyCount=0; + + /// \todo These billboards are not 100% correct, might want to revisit them later + mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1); + mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize); + mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON); + mBBSet->setCommonDirection( -position.normalisedCopy() ); + mBBSet->setVisibilityFlags(RV_Sky); + mNode = rootNode->createChildSceneNode(); + mNode->setPosition(finalPosition); + mNode->attachObject(mBBSet); + mBBSet->createBillboard(0,0,0); + mBBSet->setCastShadows(false); + + mMaterial = sh::Factory::getInstance().createMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount), material); + mMaterial->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); + + sh::Factory::getInstance().getMaterialInstance ("BillboardMaterial"+StringConverter::toString(bodyCount))->setListener(this); + + mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); + + bodyCount++; } BillboardObject::BillboardObject() { } +void BillboardObject::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) +{ +} + +void BillboardObject::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) +{ + setVisibility(mVisibility); + setColour(mColour); +} + void BillboardObject::setVisible(const bool visible) { mBBSet->setVisible(visible); @@ -42,7 +90,14 @@ void BillboardObject::setSize(const float size) void BillboardObject::setVisibility(const float visibility) { - mMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, visibility); + mVisibility = visibility; + Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); + for (int i=0; igetNumTechniques(); ++i) + { + Ogre::Technique* t = m->getTechnique(i); + if (t->getNumPasses ()) + t->getPass(0)->setDiffuse (0,0,0, visibility); + } } void BillboardObject::setPosition(const Vector3& pPosition) @@ -68,7 +123,14 @@ void BillboardObject::setVisibilityFlags(int flags) void BillboardObject::setColour(const ColourValue& pColour) { - mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour); + mColour = pColour; + Ogre::MaterialPtr m = static_cast(mMaterial->getMaterial ())->getOgreMaterial (); + for (int i=0; igetNumTechniques(); ++i) + { + Ogre::Technique* t = m->getTechnique(i); + if (t->getNumPasses ()) + t->getPass(0)->setSelfIllumination (pColour); + } } void BillboardObject::setRenderQueue(unsigned int id) @@ -81,178 +143,13 @@ SceneNode* BillboardObject::getNode() return mNode; } -void BillboardObject::init(const String& textureName, - const float initialSize, - const Vector3& position, - SceneNode* rootNode) -{ - SceneManager* sceneMgr = rootNode->getCreator(); - - Vector3 finalPosition = position.normalisedCopy() * 1000.f; - - static unsigned int bodyCount=0; - - /// \todo These billboards are not 100% correct, might want to revisit them later - mBBSet = sceneMgr->createBillboardSet("SkyBillboardSet"+StringConverter::toString(bodyCount), 1); - mBBSet->setDefaultDimensions(550.f*initialSize, 550.f*initialSize); - mBBSet->setBillboardType(BBT_PERPENDICULAR_COMMON); - mBBSet->setCommonDirection( -position.normalisedCopy() ); - mBBSet->setVisibilityFlags(RV_Sky); - mNode = rootNode->createChildSceneNode(); - mNode->setPosition(finalPosition); - mNode->attachObject(mBBSet); - mBBSet->createBillboard(0,0,0); - mBBSet->setCastShadows(false); - - mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - mMaterial->removeAllTechniques(); - Pass* p = mMaterial->createTechnique()->createPass(); - p->setSceneBlending(SBT_TRANSPARENT_ALPHA); - p->setDepthCheckEnabled(false); - p->setDepthWriteEnabled(false); - p->setSelfIllumination(1.0,1.0,1.0); - p->setDiffuse(0.0,0.0,0.0,1.0); - p->setAmbient(0.0,0.0,0.0); - p->setPolygonModeOverrideable(false); - p->createTextureUnitState(textureName); - mBBSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); - - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - HighLevelGpuProgramPtr vshader; - if (mgr.resourceExists("BBO_VP")) - vshader = mgr.getByName("BBO_VP"); - else - vshader = mgr.createProgram("BBO_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM); - vshader->setParameter("profiles", "vs_2_x arbvp1"); - vshader->setParameter("entry_point", "main_vp"); - StringUtil::StrStreamType outStream; - outStream << - "void main_vp( \n" - " float4 position : POSITION, \n" - " in float2 uv : TEXCOORD0, \n" - " out float2 oUV : TEXCOORD0, \n" - " out float4 oPosition : POSITION, \n" - " uniform float4x4 worldViewProj \n" - ") \n" - "{ \n" - " oUV = uv; \n" - " oPosition = mul( worldViewProj, position ); \n" - "}"; - vshader->setSource(outStream.str()); - vshader->load(); - vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - mMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName()); - - HighLevelGpuProgramPtr fshader; - if (mgr.resourceExists("BBO_FP")) - fshader = mgr.getByName("BBO_FP"); - else - fshader = mgr.createProgram("BBO_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_FRAGMENT_PROGRAM); - - fshader->setParameter("profiles", "ps_2_x arbfp1"); - fshader->setParameter("entry_point", "main_fp"); - StringUtil::StrStreamType outStream2; - outStream2 << - "void main_fp( \n" - " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n"; - if (RenderingManager::useMRT()) outStream2 << - " out float4 oColor1 : COLOR1, \n"; - outStream2 << - " uniform sampler2D texture : TEXUNIT0, \n" - " uniform float4 diffuse, \n" - " uniform float4 emissive \n" - ") \n" - "{ \n" - " float4 tex = tex2D(texture, uv); \n" - " oColor = float4(emissive.xyz,1) * tex * float4(1,1,1,diffuse.a); \n"; - if (RenderingManager::useMRT()) outStream2 << - " oColor1 = float4(1, 0, 0, 1); \n"; - outStream2 << - "}"; - fshader->setSource(outStream2.str()); - fshader->load(); - fshader->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR); - fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - mMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName()); - - bodyCount++; -} - Moon::Moon( const String& textureName, const float initialSize, const Vector3& position, - SceneNode* rootNode) + SceneNode* rootNode, + const std::string& material) + : BillboardObject(textureName, initialSize, position, rootNode, material) { - init(textureName, initialSize, position, rootNode); - - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - HighLevelGpuProgramPtr vshader; - if (mgr.resourceExists("Moon_VP")) - vshader = mgr.getByName("Moon_VP"); - else - vshader = mgr.createProgram("Moon_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_VERTEX_PROGRAM); - vshader->setParameter("profiles", "vs_2_x arbvp1"); - vshader->setParameter("entry_point", "main_vp"); - StringUtil::StrStreamType outStream; - outStream << - "void main_vp( \n" - " float4 position : POSITION, \n" - " in float2 uv : TEXCOORD0, \n" - " out float2 oUV : TEXCOORD0, \n" - " out float4 oPosition : POSITION, \n" - " uniform float4x4 worldViewProj \n" - ") \n" - "{ \n" - " oUV = uv; \n" - " oPosition = mul( worldViewProj, position ); \n" - "}"; - vshader->setSource(outStream.str()); - vshader->load(); - vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - mMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName()); - - HighLevelGpuProgramPtr fshader; - if (mgr.resourceExists("Moon_FP")) - fshader = mgr.getByName("Moon_FP"); - else - fshader = mgr.createProgram("Moon_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, "cg", GPT_FRAGMENT_PROGRAM); - - fshader->setParameter("profiles", "ps_2_x arbfp1"); - fshader->setParameter("entry_point", "main_fp"); - StringUtil::StrStreamType outStream2; - outStream2 << - "void main_fp( \n" - " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n"; - if (RenderingManager::useMRT()) outStream2 << - " out float4 oColor1 : COLOR1, \n"; - outStream2 << - " uniform sampler2D texture : TEXUNIT0, \n" - " uniform float4 skyColour, \n" - " uniform float4 diffuse, \n" - " uniform float4 emissive \n" - ") \n" - "{ \n" - " float4 tex = tex2D(texture, uv); \n" - " oColor = float4(emissive.xyz,1) * tex; \n"; - if (RenderingManager::useMRT()) outStream2 << - " oColor1 = float4(1, 0, 0, 1); \n"; - outStream2 << - // use a circle for the alpha (compute UV distance to center) - // looks a bit bad because its not filtered on the edges, - // but it's cheaper than a seperate alpha texture. - " float sqrUVdist = pow(uv.x-0.5,2) + pow(uv.y-0.5, 2); \n" - " oColor.a = diffuse.a * (sqrUVdist >= 0.24 ? 0 : 1); \n" - " oColor.rgb += (1-tex.a) * oColor.a * skyColour.rgb; \n"//fill dark side of moon with skycolour - " oColor.rgb += (1-diffuse.a) * skyColour.rgb; \n"//fade bump - "}"; - fshader->setSource(outStream2.str()); - fshader->load(); - fshader->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR); - fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - mMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName()); - setVisibility(1.0); mPhase = Moon::Phase_Full; @@ -263,11 +160,6 @@ void Moon::setType(const Moon::Type& type) mType = type; } -void Moon::setSkyColour(const Ogre::ColourValue& colour) -{ - mMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("skyColour", colour); -} - void Moon::setPhase(const Moon::Phase& phase) { // Colour texture @@ -287,7 +179,10 @@ void Moon::setPhase(const Moon::Phase& phase) textureName += ".dds"; - mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(textureName); + if (mType == Moon::Type_Secunda) + sh::Factory::getInstance ().setTextureAlias ("secunda_texture", textureName); + else + sh::Factory::getInstance ().setTextureAlias ("masser_texture", textureName); mPhase = phase; } @@ -336,25 +231,12 @@ void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) else if (i>= 33 && i <= 48) alpha = 64; // second bottom-most row else alpha = 255; } - + // NB we would have to swap R and B depending on rendersystem specific VertexElementType, but doesn't matter since they are both 1 uint8 tmpR = static_cast(255); uint8 tmpG = static_cast(255); uint8 tmpB = static_cast(255); uint8 tmpA = static_cast(alpha); - // This does not matter since R and B are always 1. - /*VertexElementType format = Root::getSingleton().getRenderSystem()->getColourVertexElementType(); - switch (format) - { - case VET_COLOUR_ARGB: - std::swap(tmpR, tmpB); - break; - case VET_COLOUR_ABGR: - break; - default: - break; - }*/ - // Modify *((uint32*)currentVertex) = tmpR | (tmpG << 8) | (tmpB << 16) | (tmpA << 24); @@ -379,8 +261,6 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) , mSceneMgr(NULL) , mAtmosphereDay(NULL) , mAtmosphereNight(NULL) - , mCloudMaterial() - , mAtmosphereMaterial() , mCloudFragmentShader() , mClouds() , mNextClouds() @@ -388,8 +268,6 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) , mCloudOpacity(0.0f) , mCloudSpeed(0.0f) , mStarsOpacity(0.0f) - , mThunderOverlay(NULL) - , mThunderTextureUnit(NULL) , mRemainingTransitionTime(0.0f) , mGlareFade(0.0f) , mGlare(0.0f) @@ -398,6 +276,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) , mMasserEnabled(true) , mSecundaEnabled(true) , mCreated(false) + , mCloudAnimationTimer(0.f) + , mMoonRed(false) { mSceneMgr = pMwRoot->getCreator(); mRootNode = mCamera->getParentSceneNode()->createChildSceneNode(); @@ -407,285 +287,96 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) void SkyManager::create() { - /// \todo preload all the textures and meshes that are used for sky rendering + assert(!mCreated); - // Create overlay used for thunderstorm - MaterialPtr material = MaterialManager::getSingleton().create( "ThunderMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); - Pass* pass = material->getTechnique(0)->getPass(0); - pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); - mThunderTextureUnit = pass->createTextureUnitState(); - mThunderTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(1.f, 1.f, 1.f)); - mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 0.5f); - OverlayManager& ovm = OverlayManager::getSingleton(); - mThunderOverlay = ovm.create( "ThunderOverlay" ); - OverlayContainer* overlay_panel; - overlay_panel = (OverlayContainer*)ovm.createOverlayElement("Panel", "ThunderPanel"); - overlay_panel->_setPosition(0, 0); - overlay_panel->_setDimensions(1, 1); - overlay_panel->setMaterialName( "ThunderMaterial" ); - overlay_panel->show(); - mThunderOverlay->add2D(overlay_panel); - mThunderOverlay->hide(); + sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", + sh::makeProperty(new sh::FloatValue(0))); + sh::Factory::getInstance().setSharedParameter ("cloudOpacity", + sh::makeProperty(new sh::FloatValue(1))); + sh::Factory::getInstance().setSharedParameter ("cloudColour", + sh::makeProperty(new sh::Vector3(1,1,1))); + sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", + sh::makeProperty(new sh::FloatValue(0))); + sh::Factory::getInstance().setSharedParameter ("nightFade", + sh::makeProperty(new sh::FloatValue(0))); + sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4(0,0,0,1))); - mSecunda = new Moon("textures\\tx_secunda_full.dds", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode); + sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", ""); + sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", ""); + + // Create light used for thunderstorm + mLightning = mSceneMgr->createLight(); + mLightning->setType (Ogre::Light::LT_DIRECTIONAL); + mLightning->setDirection (Ogre::Vector3(0.3, -0.7, 0.3)); + mLightning->setVisible (false); + mLightning->setDiffuseColour (ColourValue(3,3,3)); + + mSecunda = new Moon("secunda_texture", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); - mMasser = new Moon("textures\\tx_masser_full.dds", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode); + mMasser = new Moon("masser_texture", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mMasser->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); - mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode); + mSun = new BillboardObject("textures\\tx_sun_05.dds", 1, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); mSun->setRenderQueue(RQG_SkiesEarly+4); - mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode); + mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun"); mSunGlare->setRenderQueue(RQG_SkiesLate); - mSunGlare->setVisibilityFlags(RV_Glare); - - - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); + mSunGlare->setVisibilityFlags(RV_NoReflection); // Stars - /// \todo sky_night_02.nif (available in Bloodmoon) - MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif"); - Entity* night1_ent = mSceneMgr->createEntity("meshes\\sky_night_01.nif"); - night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); - night1_ent->setVisibilityFlags(RV_Sky); - night1_ent->setCastShadows(false); - mAtmosphereNight = mRootNode->createChildSceneNode(); - mAtmosphereNight->attachObject(night1_ent); - - // Stars vertex shader - HighLevelGpuProgramPtr stars_vp = mgr.createProgram("Stars_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_VERTEX_PROGRAM); - stars_vp->setParameter("profiles", "vs_2_x arbvp1"); - stars_vp->setParameter("entry_point", "main_vp"); - StringUtil::StrStreamType outStream4; - outStream4 << - "void main_vp( \n" - " float4 position : POSITION, \n" - " in float2 uv : TEXCOORD0, \n" - " out float2 oUV : TEXCOORD0, \n" - " out float oFade : TEXCOORD1, \n" - " out float4 oPosition : POSITION, \n" - " uniform float4x4 worldViewProj \n" - ") \n" - "{ \n" - " oUV = uv; \n" - " oFade = (position.z > 50) ? 1.f : 0.f; \n" - " oPosition = mul( worldViewProj, position ); \n" - "}"; - stars_vp->setSource(outStream4.str()); - stars_vp->load(); - stars_vp->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - - // Stars fragment shader - HighLevelGpuProgramPtr stars_fp = mgr.createProgram("Stars_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_FRAGMENT_PROGRAM); - stars_fp->setParameter("profiles", "ps_2_x arbfp1"); - stars_fp->setParameter("entry_point", "main_fp"); - StringUtil::StrStreamType outStream5; - outStream5 << - "void main_fp( \n" - " in float2 uv : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n"; - if (RenderingManager::useMRT()) outStream5 << - " out float4 oColor1 : COLOR1, \n"; - outStream5 << - " in float fade : TEXCOORD1, \n" - " uniform sampler2D texture : TEXUNIT0, \n" - " uniform float opacity, \n" - " uniform float4 diffuse, \n" - " uniform float4 emissive \n" - ") \n" - "{ \n" - " oColor = tex2D(texture, uv) * float4(emissive.xyz, 1) * float4(1,1,1,fade*diffuse.a); \n"; - if (RenderingManager::useMRT()) outStream5 << - " oColor1 = float4(1, 0, 0, 1); \n"; - outStream5 << - "}"; - stars_fp->setSource(outStream5.str()); - stars_fp->load(); - stars_fp->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - stars_fp->getDefaultParameters()->setNamedAutoConstant("diffuse", GpuProgramParameters::ACT_SURFACE_DIFFUSE_COLOUR); - - for (unsigned int i=0; igetNumSubEntities(); ++i) + NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(mAtmosphereNight, NULL, "meshes\\sky_night_01.nif"); + for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) { - MaterialPtr mp = night1_ent->getSubEntity(i)->getMaterial(); - mp->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); - mp->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0); - mp->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 1.0); - mp->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mp->getTechnique(0)->getPass(0)->setDepthCheckEnabled(false); - mp->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); - mp->getTechnique(0)->getPass(0)->setVertexProgram(stars_vp->getName()); - mp->getTechnique(0)->getPass(0)->setFragmentProgram(stars_fp->getName()); - mp->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); - mStarsMaterials[i] = mp; + Entity* night1_ent = entities.mEntities[i]; + night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); + night1_ent->setVisibilityFlags(RV_Sky); + night1_ent->setCastShadows(false); + + for (unsigned int j=0; jgetNumSubEntities(); ++j) + { + std::string matName = "openmw_stars_" + boost::lexical_cast(matidx++); + sh::MaterialInstance* m = sh::Factory::getInstance().createMaterialInstance(matName, "openmw_stars"); + + std::string textureName = sh::retrieveValue( + sh::Factory::getInstance().getMaterialInstance(night1_ent->getSubEntity(j)->getMaterialName())->getProperty("diffuseMap"), NULL).get(); + + m->setProperty("texture", sh::makeProperty(new sh::StringValue(textureName))); + + night1_ent->getSubEntity(j)->setMaterialName(matName); + } } + // Atmosphere (day) - mesh = NifOgre::NIFLoader::load("meshes\\sky_atmosphere.nif"); - Entity* atmosphere_ent = mSceneMgr->createEntity("meshes\\sky_atmosphere.nif"); - atmosphere_ent->setCastShadows(false); - - ModVertexAlpha(atmosphere_ent, 0); - - atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); - atmosphere_ent->setVisibilityFlags(RV_Sky); mAtmosphereDay = mRootNode->createChildSceneNode(); - mAtmosphereDay->attachObject(atmosphere_ent); - mAtmosphereMaterial = atmosphere_ent->getSubEntity(0)->getMaterial(); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); + entities = NifOgre::NIFLoader::createEntities(mAtmosphereDay, NULL, "meshes\\sky_atmosphere.nif"); + for(size_t i = 0;i < entities.mEntities.size();i++) + { + Entity* atmosphere_ent = entities.mEntities[i]; + atmosphere_ent->setCastShadows(false); + atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); + atmosphere_ent->setVisibilityFlags(RV_Sky); + atmosphere_ent->getSubEntity (0)->setMaterialName ("openmw_atmosphere"); + ModVertexAlpha(atmosphere_ent, 0); + } - // Atmosphere shader - HighLevelGpuProgramPtr vshader = mgr.createProgram("Atmosphere_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_VERTEX_PROGRAM); - - vshader->setParameter("profiles", "vs_2_x arbvp1"); - vshader->setParameter("entry_point", "main_vp"); - - StringUtil::StrStreamType outStream; - outStream << - "void main_vp( \n" - " float4 position : POSITION, \n" - " in float4 color : COLOR, \n" - " out float4 oPosition : POSITION, \n" - " out float4 oVertexColor : TEXCOORD0, \n" - " uniform float4x4 worldViewProj \n" - ") \n" - "{ \n" - " oPosition = mul( worldViewProj, position ); \n" - " oVertexColor = color; \n" - "}"; - vshader->setSource(outStream.str()); - vshader->load(); - - vshader->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader->getName()); - - HighLevelGpuProgramPtr fshader = mgr.createProgram("Atmosphere_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_FRAGMENT_PROGRAM); - - fshader->setParameter("profiles", "ps_2_x arbfp1"); - fshader->setParameter("entry_point", "main_fp"); - - StringUtil::StrStreamType _outStream; - _outStream << - "void main_fp( \n" - " in float4 iVertexColor : TEXCOORD0, \n" - " out float4 oColor : COLOR, \n"; - if (RenderingManager::useMRT()) _outStream << - " out float4 oColor1 : COLOR1, \n"; - _outStream << - " uniform float4 emissive \n" - ") \n" - "{ \n" - " oColor = iVertexColor * emissive; \n"; - if (RenderingManager::useMRT()) _outStream << - " oColor1 = float4(1, 0, 0, 1); \n"; - _outStream << - "}"; - fshader->setSource(_outStream.str()); - fshader->load(); - - fshader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(fshader->getName()); // Clouds - NifOgre::NIFLoader::load("meshes\\sky_clouds_01.nif"); - Entity* clouds_ent = mSceneMgr->createEntity("meshes\\sky_clouds_01.nif"); - clouds_ent->setVisibilityFlags(RV_Sky); - clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); SceneNode* clouds_node = mRootNode->createChildSceneNode(); - clouds_node->attachObject(clouds_ent); - mCloudMaterial = clouds_ent->getSubEntity(0)->getMaterial(); - mCloudMaterial->getTechnique(0)->getPass(0)->setPolygonModeOverrideable(false); - clouds_ent->setCastShadows(false); + entities = NifOgre::NIFLoader::createEntities(clouds_node, NULL, "meshes\\sky_clouds_01.nif"); + for(size_t i = 0;i < entities.mEntities.size();i++) + { + Entity* clouds_ent = entities.mEntities[i]; + clouds_ent->setVisibilityFlags(RV_Sky); + clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); + clouds_ent->getSubEntity(0)->setMaterialName ("openmw_clouds"); + clouds_ent->setCastShadows(false); - // Clouds vertex shader - HighLevelGpuProgramPtr vshader2 = mgr.createProgram("Clouds_VP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_VERTEX_PROGRAM); - vshader2->setParameter("profiles", "vs_2_x arbvp1"); - vshader2->setParameter("entry_point", "main_vp"); - StringUtil::StrStreamType outStream3; - outStream3 << - "void main_vp( \n" - " float4 position : POSITION, \n" - " in float4 color : COLOR, \n" - " out float4 oColor : TEXCOORD1, \n" - " in float2 uv : TEXCOORD0, \n" - " out float2 oUV : TEXCOORD0, \n" - " out float4 oPosition : POSITION, \n" - " uniform float4x4 worldViewProj \n" - ") \n" - "{ \n" - " oUV = uv; \n" - " oColor = color; \n" - " oPosition = mul( worldViewProj, position ); \n" - "}"; - vshader2->setSource(outStream3.str()); - vshader2->load(); - vshader2->getDefaultParameters()->setNamedAutoConstant("worldViewProj", GpuProgramParameters::ACT_WORLDVIEWPROJ_MATRIX); - mCloudMaterial->getTechnique(0)->getPass(0)->setVertexProgram(vshader2->getName()); - - // Clouds fragment shader - mCloudFragmentShader = mgr.createProgram("Clouds_FP", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_FRAGMENT_PROGRAM); - mCloudFragmentShader->setParameter("profiles", "ps_2_x arbfp1"); - mCloudFragmentShader->setParameter("entry_point", "main_fp"); - StringUtil::StrStreamType outStream2; - outStream2 << - "void main_fp( \n" - " in float2 uv : TEXCOORD0, \n" - " in float4 color : TEXCOORD1, \n" - " out float4 oColor : COLOR, \n"; - if (RenderingManager::useMRT()) outStream2 << - " out float4 oColor1 : COLOR1, \n"; - outStream2 << - " uniform sampler2D texture : TEXUNIT0, \n" - " uniform sampler2D secondTexture : TEXUNIT1, \n" - " uniform float transitionFactor, \n" - " uniform float time, \n" - " uniform float speed, \n" - " uniform float opacity, \n" - " uniform float4 emissive \n" - ") \n" - "{ \n" - " uv += float2(0,1) * time * speed * 0.003; \n" // Scroll in y direction - " float4 tex = lerp(tex2D(texture, uv), tex2D(secondTexture, uv), transitionFactor); \n" - " oColor = color * float4(emissive.xyz,1) * tex * float4(1,1,1,opacity); \n"; - if (RenderingManager::useMRT()) outStream2 << - " oColor1 = float4(1, 0, 0, 1); \n"; - outStream2 << - "}"; - mCloudFragmentShader->setSource(outStream2.str()); - mCloudFragmentShader->load(); - mCloudFragmentShader->getDefaultParameters()->setNamedAutoConstant("emissive", GpuProgramParameters::ACT_SURFACE_EMISSIVE_COLOUR); - mCloudMaterial->getTechnique(0)->getPass(0)->setFragmentProgram(mCloudFragmentShader->getName()); - setCloudsOpacity(0.75); - - ModVertexAlpha(clouds_ent, 1); - - // I'm not sure if the materials are being used by any other objects - // Make a unique "modifiable" copy of the materials to be sure - mCloudMaterial = mCloudMaterial->clone("Clouds"); - clouds_ent->getSubEntity(0)->setMaterial(mCloudMaterial); - mAtmosphereMaterial = mAtmosphereMaterial->clone("Atmosphere"); - atmosphere_ent->getSubEntity(0)->setMaterial(mAtmosphereMaterial); - - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, 0.0); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setAmbient(0.0, 0.0, 0.0); - mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(1.0, 1.0, 1.0); - mCloudMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); - mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); - - mCloudMaterial->getTechnique(0)->getPass(0)->removeAllTextureUnitStates(); - mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("textures\\tx_sky_cloudy.dds"); - mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(""); + ModVertexAlpha(clouds_ent, 1); + } mCreated = true; } @@ -715,24 +406,28 @@ void SkyManager::update(float duration) if (!mEnabled) return; // UV Scroll the clouds - mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); + mCloudAnimationTimer += duration * mCloudSpeed * (MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f); + sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer", + sh::makeProperty(new sh::FloatValue(mCloudAnimationTimer))); /// \todo improve this mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); + mSecunda->setColour ( mMoonRed ? ColourValue(1.0, 0.0784, 0.0784) : ColourValue(1,1,1,1)); + mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) { - // take 1/5 sec for fading the glare effect from invisible to full + // take 1/10 sec for fading the glare effect from invisible to full if (mGlareFade > mGlare) { - mGlareFade -= duration*5; + mGlareFade -= duration*10; if (mGlareFade < mGlare) mGlareFade = mGlare; } else if (mGlareFade < mGlare) { - mGlareFade += duration*5; + mGlareFade += duration*10; if (mGlareFade > mGlare) mGlareFade = mGlare; } @@ -774,42 +469,37 @@ void SkyManager::disable() void SkyManager::setMoonColour (bool red) { - if (!mCreated) return; - mSecunda->setColour( red ? ColourValue(1.0, 0.0784, 0.0784) - : ColourValue(1.0, 1.0, 1.0)); -} - -void SkyManager::setCloudsOpacity(float opacity) -{ - if (!mCreated) return; - mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity)); + mMoonRed = red; } void SkyManager::setWeather(const MWWorld::WeatherResult& weather) { if (!mCreated) return; + if (mClouds != weather.mCloudTexture) { - mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture); + sh::Factory::getInstance().setTextureAlias ("cloud_texture_1", "textures\\"+weather.mCloudTexture); mClouds = weather.mCloudTexture; } if (mNextClouds != weather.mNextCloudTexture) { - mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName("textures\\"+weather.mNextCloudTexture); + sh::Factory::getInstance().setTextureAlias ("cloud_texture_2", "textures\\"+weather.mNextCloudTexture); mNextClouds = weather.mNextCloudTexture; } if (mCloudBlendFactor != weather.mCloudBlendFactor) { - mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("transitionFactor", Real(weather.mCloudBlendFactor)); mCloudBlendFactor = weather.mCloudBlendFactor; + sh::Factory::getInstance().setSharedParameter ("cloudBlendFactor", + sh::makeProperty(new sh::FloatValue(weather.mCloudBlendFactor))); } if (mCloudOpacity != weather.mCloudOpacity) { - mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(weather.mCloudOpacity)); mCloudOpacity = weather.mCloudOpacity; + sh::Factory::getInstance().setSharedParameter ("cloudOpacity", + sh::makeProperty(new sh::FloatValue(weather.mCloudOpacity))); } if (mCloudColour != weather.mSunColor) @@ -818,23 +508,20 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) weather.mSunColor.g*0.7 + weather.mAmbientColor.g*0.7, weather.mSunColor.b*0.7 + weather.mAmbientColor.b*0.7); - mCloudMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(clr); + sh::Factory::getInstance().setSharedParameter ("cloudColour", + sh::makeProperty(new sh::Vector3(clr.r, clr.g, clr.b))); + mCloudColour = weather.mSunColor; } if (mSkyColour != weather.mSkyColor) { - mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(weather.mSkyColor); - mMasser->setSkyColour(weather.mSkyColor); - mSecunda->setSkyColour(weather.mSkyColor); mSkyColour = weather.mSkyColor; + sh::Factory::getInstance().setSharedParameter ("atmosphereColour", sh::makeProperty(new sh::Vector4( + weather.mSkyColor.r, weather.mSkyColor.g, weather.mSkyColor.b, weather.mSkyColor.a))); } - if (mCloudSpeed != weather.mCloudSpeed) - { - mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("speed", Real(weather.mCloudSpeed)); - mCloudSpeed = weather.mCloudSpeed; - } + mCloudSpeed = weather.mCloudSpeed; if (weather.mNight && mStarsOpacity != weather.mNightFade) { @@ -843,12 +530,15 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) else { mAtmosphereNight->setVisible(true); - for (int i=0; i<7; ++i) - mStarsMaterials[i]->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, weather.mNightFade); + + sh::Factory::getInstance().setSharedParameter ("nightFade", + sh::makeProperty(new sh::FloatValue(weather.mNightFade))); + mStarsOpacity = weather.mNightFade; } } + float strength; float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length()); if (timeofday_angle <= 0.44) @@ -889,6 +579,10 @@ void SkyManager::setSunDirection(const Vector3& direction) if (!mCreated) return; mSun->setPosition(direction); mSunGlare->setPosition(direction); + + float height = direction.z; + float fade = ( height > 0.5) ? 1.0 : height * 2; + sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(fade, height))); } void SkyManager::setMasserDirection(const Vector3& direction) @@ -923,16 +617,22 @@ void SkyManager::secundaDisable() mSecundaEnabled = false; } -void SkyManager::setThunder(const float factor) +void SkyManager::setLightningStrength(const float factor) { if (!mCreated) return; if (factor > 0.f) { - mThunderOverlay->show(); - mThunderTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, factor*0.6); + mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor)); + mLightning->setVisible(true); } else - mThunderOverlay->hide(); + mLightning->setVisible(false); +} + +void SkyManager::setLightningDirection(const Ogre::Vector3& dir) +{ + if (!mCreated) return; + mLightning->setDirection (dir); } void SkyManager::setMasserFade(const float fade) @@ -978,3 +678,10 @@ void SkyManager::scaleSky(float scale) { mRootNode->setScale(scale, scale, scale); } + +void SkyManager::setGlareEnabled (bool enabled) +{ + if (!mCreated) + return; + mSunGlare->setVisible (mSunEnabled && enabled); +} diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index e11745e82..09d56dbd9 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,13 +1,17 @@ #ifndef _GAME_RENDER_SKY_H #define _GAME_RENDER_SKY_H +#include + #include #include #include #include #include -#include "sky.hpp" +#include + + #include "../mwworld/weather.hpp" namespace Ogre @@ -25,16 +29,20 @@ namespace Ogre namespace MWRender { - class BillboardObject + class BillboardObject : public sh::MaterialInstanceListener { public: BillboardObject( const Ogre::String& textureName, const float size, const Ogre::Vector3& position, - Ogre::SceneNode* rootNode + Ogre::SceneNode* rootNode, + const std::string& material ); BillboardObject(); + void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration); + void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration); + virtual ~BillboardObject() {} void setColour(const Ogre::ColourValue& pColour); @@ -50,13 +58,10 @@ namespace MWRender Ogre::SceneNode* getNode(); protected: - virtual void init(const Ogre::String& textureName, - const float size, - const Ogre::Vector3& position, - Ogre::SceneNode* rootNode); - + float mVisibility; + Ogre::ColourValue mColour; Ogre::SceneNode* mNode; - Ogre::MaterialPtr mMaterial; + sh::MaterialInstance* mMaterial; Ogre::BillboardSet* mBBSet; }; @@ -70,7 +75,8 @@ namespace MWRender Moon( const Ogre::String& textureName, const float size, const Ogre::Vector3& position, - Ogre::SceneNode* rootNode + Ogre::SceneNode* rootNode, + const std::string& material ); virtual ~Moon() {} @@ -95,7 +101,6 @@ namespace MWRender void setPhase(const Phase& phase); void setType(const Type& type); - void setSkyColour(const Ogre::ColourValue& colour); Phase getPhase() const; unsigned int getPhaseInt() const; @@ -137,9 +142,6 @@ namespace MWRender void setMoonColour (bool red); ///< change Secunda colour to red - void setCloudsOpacity(float opacity); - ///< change opacity of the clouds - void setWeather(const MWWorld::WeatherResult& weather); Ogre::SceneNode* getSunNode(); @@ -164,9 +166,11 @@ namespace MWRender void secundaEnable(); void secundaDisable(); - void setThunder(const float factor); + void setLightningStrength(const float factor); + void setLightningDirection(const Ogre::Vector3& dir); void setGlare(const float glare); + void setGlareEnabled(bool enabled); Ogre::Vector3 getRealSunPos(); void setSkyPosition(const Ogre::Vector3& position); @@ -176,10 +180,14 @@ namespace MWRender private: bool mCreated; + bool mMoonRed; + float mHour; int mDay; int mMonth; + float mCloudAnimationTimer; + BillboardObject* mSun; BillboardObject* mSunGlare; Moon* mMasser; @@ -192,11 +200,6 @@ namespace MWRender Ogre::SceneNode* mAtmosphereDay; Ogre::SceneNode* mAtmosphereNight; - Ogre::MaterialPtr mCloudMaterial; - Ogre::MaterialPtr mAtmosphereMaterial; - - Ogre::MaterialPtr mStarsMaterials[7]; - Ogre::HighLevelGpuProgramPtr mCloudFragmentShader; // remember some settings so we don't have to apply them again if they didnt change @@ -209,8 +212,7 @@ namespace MWRender Ogre::ColourValue mCloudColour; Ogre::ColourValue mSkyColour; - Ogre::Overlay* mThunderOverlay; - Ogre::TextureUnitState* mThunderTextureUnit; + Ogre::Light* mLightning; float mRemainingTransitionTime; diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 4dac750c7..691e7c4af 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -1,16 +1,21 @@ -#include -#include #include -#include "../mwworld/world.hpp" +#include +#include +#include + +#include + +#include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "terrainmaterial.hpp" #include "terrain.hpp" #include "renderconst.hpp" #include "shadows.hpp" -#include +#include "renderingmanager.hpp" using namespace Ogre; @@ -23,22 +28,22 @@ namespace MWRender mTerrainGroup(TerrainGroup(mgr, Terrain::ALIGN_X_Z, mLandSize, mWorldSize)), mRendering(rend) { mTerrainGlobals = OGRE_NEW TerrainGlobalOptions(); + TerrainMaterialGeneratorPtr matGen; - TerrainMaterialGeneratorB* matGenP = new TerrainMaterialGeneratorB(); + TerrainMaterial* matGenP = new TerrainMaterial(); matGen.bind(matGenP); mTerrainGlobals->setDefaultMaterialGenerator(matGen); TerrainMaterialGenerator::Profile* const activeProfile = mTerrainGlobals->getDefaultMaterialGenerator() ->getActiveProfile(); - mActiveProfile = static_cast(activeProfile); + mActiveProfile = static_cast(activeProfile); //The pixel error should be as high as possible without it being noticed //as it governs how fast mesh quality decreases. mTerrainGlobals->setMaxPixelError(8); mTerrainGlobals->setLayerBlendMapSize(32); - mTerrainGlobals->setDefaultGlobalColourMapSize(65); //10 (default) didn't seem to be quite enough mTerrainGlobals->setSkirtSize(128); @@ -47,26 +52,6 @@ namespace MWRender //this seemed the distance where it wasn't too noticeable mTerrainGlobals->setCompositeMapDistance(mWorldSize*2); - mActiveProfile->setLightmapEnabled(false); - mActiveProfile->setLayerSpecularMappingEnabled(false); - mActiveProfile->setLayerNormalMappingEnabled(false); - mActiveProfile->setLayerParallaxMappingEnabled(false); - - bool shadows = Settings::Manager::getBool("enabled", "Shadows"); - mActiveProfile->setReceiveDynamicShadowsEnabled(shadows); - mActiveProfile->setReceiveDynamicShadowsDepth(shadows); - if (Settings::Manager::getBool("split", "Shadows")) - mActiveProfile->setReceiveDynamicShadowsPSSM(mRendering->getShadows()->getPSSMSetup()); - else - mActiveProfile->setReceiveDynamicShadowsPSSM(0); - - mActiveProfile->setShadowFar(mRendering->getShadows()->getShadowFar()); - mActiveProfile->setShadowFadeStart(mRendering->getShadows()->getFadeStart()); - - //composite maps lead to a drastic increase in loading time so are - //disabled - mActiveProfile->setCompositeMapEnabled(false); - mTerrainGroup.setOrigin(Vector3(mWorldSize/2, 0, -mWorldSize/2)); @@ -173,23 +158,20 @@ namespace MWRender terrain->setVisibilityFlags(RV_Terrain); terrain->setRenderQueueGroup(RQG_Main); + // disable or enable global colour map (depends on available vertex colours) if ( land->landData->usingColours ) { - // disable or enable global colour map (depends on available vertex colours) - mActiveProfile->setGlobalColourMapEnabled(true); TexturePtr vertex = getVertexColours(land, cellX, cellY, x*(mLandSize-1), y*(mLandSize-1), mLandSize); - //this is a hack to get around the fact that Ogre seems to - //corrupt the global colour map leading to rendering errors - MaterialPtr mat = terrain->getMaterial(); - mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName( vertex->getName() ); - //mat = terrain->_getCompositeMapMaterial(); - //mat->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName( vertex->getName() ); + mActiveProfile->setGlobalColourMapEnabled(true); + mActiveProfile->setGlobalColourMap (terrain, vertex->getName()); } + else + mActiveProfile->setGlobalColourMapEnabled (false); } } } diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index 273ede084..c83d96cf4 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -3,9 +3,10 @@ #include #include -#include "terrainmaterial.hpp" -#include "../mwworld/ptr.hpp" +#include + +#include "terrainmaterial.hpp" namespace Ogre{ class SceneManager; @@ -14,8 +15,15 @@ namespace Ogre{ class Terrain; } +namespace MWWorld +{ + class CellStore; +} + namespace MWRender{ + class RenderingManager; + /** * Implements the Morrowind terrain using the Ogre Terrain Component * @@ -30,15 +38,15 @@ namespace MWRender{ void setDiffuse(const Ogre::ColourValue& diffuse); void setAmbient(const Ogre::ColourValue& ambient); - void cellAdded(MWWorld::Ptr::CellStore* store); - void cellRemoved(MWWorld::Ptr::CellStore* store); + void cellAdded(MWWorld::CellStore* store); + void cellRemoved(MWWorld::CellStore* store); private: Ogre::TerrainGlobalOptions* mTerrainGlobals; Ogre::TerrainGroup mTerrainGroup; RenderingManager* mRendering; - Ogre::TerrainMaterialGeneratorB::SM2Profile* mActiveProfile; + TerrainMaterial::Profile* mActiveProfile; /** * The length in verticies of a single terrain block. diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index a3265b2a5..5ef9fe58f 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -1,1746 +1,180 @@ -/* ------------------------------------------------------------------------------ -This source file is part of OGRE -(Object-oriented Graphics Rendering Engine) -For the latest info, see http://www.ogre3d.org/ - -Copyright (c) 2000-2011 Torus Knot Software Ltd - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. ------------------------------------------------------------------------------ -*/ #include "terrainmaterial.hpp" -#include "OgreTerrain.h" -#include "OgreMaterialManager.h" -#include "OgreTechnique.h" -#include "OgrePass.h" -#include "OgreTextureUnitState.h" -#include "OgreGpuProgramManager.h" -#include "OgreHighLevelGpuProgramManager.h" -#include "OgreHardwarePixelBuffer.h" -#include "OgreShadowCameraSetupPSSM.h" -#include -#include "renderingmanager.hpp" +#include -#undef far +#include -namespace Ogre +#include + +namespace { - //--------------------------------------------------------------------- - TerrainMaterialGeneratorB::TerrainMaterialGeneratorB() - { - // define the layers - // We expect terrain textures to have no alpha, so we use the alpha channel - // in the albedo texture to store specular reflection - // similarly we double-up the normal and height (for parallax) - mLayerDecl.samplers.push_back(TerrainLayerSampler("albedo_specular", PF_BYTE_RGBA)); - //mLayerDecl.samplers.push_back(TerrainLayerSampler("normal_height", PF_BYTE_RGBA)); - - mLayerDecl.elements.push_back( - TerrainLayerSamplerElement(0, TLSS_ALBEDO, 0, 3)); - //mLayerDecl.elements.push_back( - // TerrainLayerSamplerElement(0, TLSS_SPECULAR, 3, 1)); - //mLayerDecl.elements.push_back( - // TerrainLayerSamplerElement(1, TLSS_NORMAL, 0, 3)); - //mLayerDecl.elements.push_back( - // TerrainLayerSamplerElement(1, TLSS_HEIGHT, 3, 1)); - - - mProfiles.push_back(OGRE_NEW SM2Profile(this, "SM2", "Profile for rendering on Shader Model 2 capable cards")); - // TODO - check hardware capabilities & use fallbacks if required (more profiles needed) - setActiveProfile("SM2"); - - } - //--------------------------------------------------------------------- - TerrainMaterialGeneratorB::~TerrainMaterialGeneratorB() - { - - } - //--------------------------------------------------------------------- - //--------------------------------------------------------------------- - TerrainMaterialGeneratorB::SM2Profile::SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc) - : Profile(parent, name, desc) - , mShaderGen(0) - , mLayerNormalMappingEnabled(true) - , mLayerParallaxMappingEnabled(true) - , mLayerSpecularMappingEnabled(true) - , mGlobalColourMapEnabled(true) - , mLightmapEnabled(true) - , mCompositeMapEnabled(true) - , mReceiveDynamicShadows(true) - , mPSSM(0) - , mDepthShadows(false) - , mLowLodShadows(false) - , mShadowFar(1300) - { - - } - //--------------------------------------------------------------------- - TerrainMaterialGeneratorB::SM2Profile::~SM2Profile() - { - OGRE_DELETE mShaderGen; - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::requestOptions(Terrain* terrain) - { - terrain->_setMorphRequired(true); - terrain->_setNormalMapRequired(true); - terrain->_setLightMapRequired(mLightmapEnabled, true); - terrain->_setCompositeMapRequired(mCompositeMapEnabled); - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setShadowFar(float far) + Ogre::String getComponent (int num) { - if (mShadowFar != far) + if (num == 0) + return "x"; + else if (num == 1) + return "y"; + else if (num == 2) + return "z"; + else + return "w"; + } +} + + +namespace MWRender +{ + + TerrainMaterial::TerrainMaterial() + { + mLayerDecl.samplers.push_back(Ogre::TerrainLayerSampler("albedo_specular", Ogre::PF_BYTE_RGBA)); + //mLayerDecl.samplers.push_back(Ogre::TerrainLayerSampler("normal_height", Ogre::PF_BYTE_RGBA)); + + mLayerDecl.elements.push_back( + Ogre::TerrainLayerSamplerElement(0, Ogre::TLSS_ALBEDO, 0, 3)); + //mLayerDecl.elements.push_back( + // Ogre::TerrainLayerSamplerElement(0, Ogre::TLSS_SPECULAR, 3, 1)); + //mLayerDecl.elements.push_back( + // Ogre::TerrainLayerSamplerElement(1, Ogre::TLSS_NORMAL, 0, 3)); + //mLayerDecl.elements.push_back( + // Ogre::TerrainLayerSamplerElement(1, Ogre::TLSS_HEIGHT, 3, 1)); + + + mProfiles.push_back(OGRE_NEW Profile(this, "SM2", "Profile for rendering on Shader Model 2 capable cards")); + setActiveProfile("SM2"); + } + + // ----------------------------------------------------------------------------------------------------------------------- + + TerrainMaterial::Profile::Profile(Ogre::TerrainMaterialGenerator* parent, const Ogre::String& name, const Ogre::String& desc) + : Ogre::TerrainMaterialGenerator::Profile(parent, name, desc) + , mGlobalColourMap(false) + { + } + + TerrainMaterial::Profile::~Profile() + { + } + + + Ogre::MaterialPtr TerrainMaterial::Profile::generate(const Ogre::Terrain* terrain) + { + const Ogre::String& matName = terrain->getMaterialName(); + + sh::Factory::getInstance().destroyMaterialInstance (matName); + + Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().getByName(matName); + if (!mat.isNull()) + Ogre::MaterialManager::getSingleton().remove(matName); + + mMaterial = sh::Factory::getInstance().createMaterialInstance (matName); + + mMaterial->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); + + sh::MaterialInstancePass* p = mMaterial->createPass (); + + p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); + p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); + + p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap))); + + // global colour map + sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap"); + colourMap->setProperty ("texture_alias", sh::makeProperty (new sh::StringValue(mMaterial->getName() + "_colourMap"))); + colourMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + // global normal map + sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap"); + normalMap->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getTerrainNormalMap ()->getName()))); + normalMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + Ogre::uint maxLayers = getMaxLayers(terrain); + Ogre::uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount()); + Ogre::uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); + + p->mShaderProperties.setProperty ("num_layers", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numLayers)))); + p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); + + // blend maps + for (Ogre::uint i = 0; i < numBlendTextures; ++i) { - mShadowFar = far; - mParent->_markChanged(); + sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); + blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(i)))); + blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setShadowFadeStart(float fadestart) - { - if (mShadowFadeStart != fadestart) + + // layer maps + for (Ogre::uint i = 0; i < numLayers; ++i) { - mShadowFadeStart = fadestart; - mParent->_markChanged(); + sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); + diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(i, 0)))); + p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), + sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(int((i-1) / 4)) + "." + getComponent(int((i-1) % 4))))); } + + // shadow + for (Ogre::uint i = 0; i < 3; ++i) + { + sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); + shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + } + + // caustics + sh::MaterialInstanceTextureUnit* caustics = p->createTextureUnit ("causticMap"); + caustics->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue("water_nm.png"))); + + p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty(new sh::StringValue( + Ogre::StringConverter::toString(numBlendTextures + numLayers + 2)))); + + return Ogre::MaterialManager::getSingleton().getByName(matName); } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setLayerNormalMappingEnabled(bool enabled) - { - if (enabled != mLayerNormalMappingEnabled) - { - mLayerNormalMappingEnabled = enabled; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setLayerParallaxMappingEnabled(bool enabled) - { - if (enabled != mLayerParallaxMappingEnabled) - { - mLayerParallaxMappingEnabled = enabled; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setLayerSpecularMappingEnabled(bool enabled) - { - if (enabled != mLayerSpecularMappingEnabled) - { - mLayerSpecularMappingEnabled = enabled; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setGlobalColourMapEnabled(bool enabled) - { - if (enabled != mGlobalColourMapEnabled) - { - mGlobalColourMapEnabled = enabled; - //mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setLightmapEnabled(bool enabled) - { - if (enabled != mLightmapEnabled) - { - mLightmapEnabled = enabled; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setCompositeMapEnabled(bool enabled) - { - if (enabled != mCompositeMapEnabled) - { - mCompositeMapEnabled = enabled; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setReceiveDynamicShadowsEnabled(bool enabled) - { - if (enabled != mReceiveDynamicShadows) - { - mReceiveDynamicShadows = enabled; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup* pssmSettings) - { - if (pssmSettings != mPSSM) - { - mPSSM = pssmSettings; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setReceiveDynamicShadowsDepth(bool enabled) - { - if (enabled != mDepthShadows) - { - mDepthShadows = enabled; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::setReceiveDynamicShadowsLowLod(bool enabled) - { - if (enabled != mLowLodShadows) - { - mLowLodShadows = enabled; - mParent->_markChanged(); - } - } - //--------------------------------------------------------------------- - uint8 TerrainMaterialGeneratorB::SM2Profile::getMaxLayers(const Terrain* terrain) const - { - // count the texture units free - uint8 freeTextureUnits = 16; - // lightmap - if (mLightmapEnabled) - --freeTextureUnits; - // normalmap - --freeTextureUnits; - // colourmap - //if (terrain->getGlobalColourMapEnabled()) - --freeTextureUnits; - if (isShadowingEnabled(HIGH_LOD, terrain)) - { - uint numShadowTextures = 1; - if (getReceiveDynamicShadowsPSSM()) - { - numShadowTextures = getReceiveDynamicShadowsPSSM()->getSplitCount(); - } - freeTextureUnits -= numShadowTextures; - } - - // each layer needs 2.25 units (1xdiffusespec, (1xnormalheight), 0.25xblend) - return static_cast(freeTextureUnits / (1.25f + (mLayerNormalMappingEnabled||mLayerParallaxMappingEnabled))); - - - } - int TerrainMaterialGeneratorB::SM2Profile::getNumberOfLightsSupported() const + void TerrainMaterial::Profile::setGlobalColourMapEnabled (bool enabled) { - return Settings::Manager::getInt("num lights", "Terrain"); + mGlobalColourMap = enabled; + mParent->_markChanged(); } - //--------------------------------------------------------------------- - MaterialPtr TerrainMaterialGeneratorB::SM2Profile::generate(const Terrain* terrain) - { - // re-use old material if exists - MaterialPtr mat = terrain->_getMaterial(); - if (mat.isNull()) - { - MaterialManager& matMgr = MaterialManager::getSingleton(); - - // it's important that the names are deterministic for a given terrain, so - // use the terrain pointer as an ID - const String& matName = terrain->getMaterialName(); - mat = matMgr.getByName(matName); - if (mat.isNull()) - { - mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - } - } - // clear everything - mat->removeAllTechniques(); - - // Automatically disable normal & parallax mapping if card cannot handle it - // We do this rather than having a specific technique for it since it's simpler - GpuProgramManager& gmgr = GpuProgramManager::getSingleton(); - if (!gmgr.isSyntaxSupported("ps_3_0") && !gmgr.isSyntaxSupported("ps_2_x") - && !gmgr.isSyntaxSupported("fp40") && !gmgr.isSyntaxSupported("arbfp1")) - { - setLayerNormalMappingEnabled(false); - setLayerParallaxMappingEnabled(false); - } - - addTechnique(mat, terrain, HIGH_LOD); - - // LOD - if(mCompositeMapEnabled) - { - addTechnique(mat, terrain, LOW_LOD); - Material::LodValueList lodValues; - lodValues.push_back(TerrainGlobalOptions::getSingleton().getCompositeMapDistance()); - mat->setLodLevels(lodValues); - Technique* lowLodTechnique = mat->getTechnique(1); - lowLodTechnique->setLodIndex(1); - } - - updateParams(mat, terrain); - - return mat; - - } - //--------------------------------------------------------------------- - MaterialPtr TerrainMaterialGeneratorB::SM2Profile::generateForCompositeMap(const Terrain* terrain) - { - // re-use old material if exists - MaterialPtr mat = terrain->_getCompositeMapMaterial(); - if (mat.isNull()) - { - MaterialManager& matMgr = MaterialManager::getSingleton(); - - // it's important that the names are deterministic for a given terrain, so - // use the terrain pointer as an ID - const String& matName = terrain->getMaterialName() + "/comp"; - mat = matMgr.getByName(matName); - if (mat.isNull()) - { - mat = matMgr.create(matName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); - } - } - // clear everything - mat->removeAllTechniques(); - - addTechnique(mat, terrain, RENDER_COMPOSITE_MAP); - - updateParamsForCompositeMap(mat, terrain); - - return mat; - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::addTechnique( - const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt) - { - - Technique* tech = mat->createTechnique(); - - // Only supporting one pass - Pass* pass = tech->createPass(); - - GpuProgramManager& gmgr = GpuProgramManager::getSingleton(); - HighLevelGpuProgramManager& hmgr = HighLevelGpuProgramManager::getSingleton(); - if (!mShaderGen) - { - bool check2x = mLayerNormalMappingEnabled || mLayerParallaxMappingEnabled; - if (hmgr.isLanguageSupported("cg")) - mShaderGen = OGRE_NEW ShaderHelperCg(); - else if (hmgr.isLanguageSupported("hlsl") && - ((check2x && gmgr.isSyntaxSupported("ps_2_x")) || - (!check2x && gmgr.isSyntaxSupported("ps_2_0")))) - mShaderGen = OGRE_NEW ShaderHelperHLSL(); - else if (hmgr.isLanguageSupported("glsl")) - mShaderGen = OGRE_NEW ShaderHelperGLSL(); - else - { - // todo - } - - // check SM3 features - mSM3Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_3_0"); - - } - HighLevelGpuProgramPtr vprog = mShaderGen->generateVertexProgram(this, terrain, tt); - HighLevelGpuProgramPtr fprog = mShaderGen->generateFragmentProgram(this, terrain, tt); - - pass->setVertexProgram(vprog->getName()); - pass->setFragmentProgram(fprog->getName()); - - if (tt == HIGH_LOD || tt == RENDER_COMPOSITE_MAP) - { - // global normal map - TextureUnitState* tu = pass->createTextureUnitState(); - tu->setTextureName(terrain->getTerrainNormalMap()->getName()); - tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); - - // global colour map - if (isGlobalColourMapEnabled()) - { - tu = pass->createTextureUnitState(""); - tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); - } - - // light map - if (isLightmapEnabled()) - { - tu = pass->createTextureUnitState(terrain->getLightmap()->getName()); - tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); - } - - // blend maps - uint maxLayers = getMaxLayers(terrain); - uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount()); - uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - for (uint i = 0; i < numBlendTextures; ++i) - { - tu = pass->createTextureUnitState(terrain->getBlendTextureName(i)); - tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); - } - - // layer textures - for (uint i = 0; i < numLayers; ++i) - { - // diffuse / specular - tu = pass->createTextureUnitState(terrain->getLayerTextureName(i, 0)); - - // normal / height - if (mLayerNormalMappingEnabled || mLayerParallaxMappingEnabled) - tu = pass->createTextureUnitState(terrain->getLayerTextureName(i, 1)); - } - - } - else - { - // LOW_LOD textures - // composite map - TextureUnitState* tu = pass->createTextureUnitState(); - tu->setTextureName(terrain->getCompositeMap()->getName()); - tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); - - // That's it! - - } - - // Add shadow textures (always at the end) - if (isShadowingEnabled(tt, terrain)) - { - uint numTextures = 1; - if (getReceiveDynamicShadowsPSSM()) - { - numTextures = getReceiveDynamicShadowsPSSM()->getSplitCount(); - } - for (uint i = 0; i < numTextures; ++i) - { - TextureUnitState* tu = pass->createTextureUnitState(); - tu->setContentType(TextureUnitState::CONTENT_SHADOW); - tu->setTextureAddressingMode(TextureUnitState::TAM_BORDER); - tu->setTextureBorderColour(ColourValue::White); - } - } - - } - //--------------------------------------------------------------------- - bool TerrainMaterialGeneratorB::SM2Profile::isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const - { - return getReceiveDynamicShadowsEnabled() && tt != RENDER_COMPOSITE_MAP && - (tt != LOW_LOD || mLowLodShadows) && - terrain->getSceneManager()->isShadowTechniqueTextureBased(); - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::updateParams(const MaterialPtr& mat, const Terrain* terrain) - { - mShaderGen->updateParams(this, mat, terrain, false); - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain) - { - mShaderGen->updateParams(this, mat, terrain, true); - } - //--------------------------------------------------------------------- - //--------------------------------------------------------------------- - HighLevelGpuProgramPtr - TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::generateVertexProgram( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - HighLevelGpuProgramPtr ret = createVertexProgram(prof, terrain, tt); - - StringUtil::StrStreamType sourceStr; - generateVertexProgramSource(prof, terrain, tt, sourceStr); - ret->setSource(sourceStr.str()); - ret->load(); - defaultVpParams(prof, terrain, tt, ret); -#if OGRE_DEBUG_MODE - LogManager::getSingleton().stream(LML_TRIVIAL) << "*** Terrain Vertex Program: " - << ret->getName() << " ***\n" << ret->getSource() << "\n*** ***"; -#endif - - return ret; - - } - //--------------------------------------------------------------------- - HighLevelGpuProgramPtr - TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::generateFragmentProgram( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - HighLevelGpuProgramPtr ret = createFragmentProgram(prof, terrain, tt); - - StringUtil::StrStreamType sourceStr; - generateFragmentProgramSource(prof, terrain, tt, sourceStr); - - ret->setSource(sourceStr.str()); - ret->load(); - defaultFpParams(prof, terrain, tt, ret); - -#if OGRE_DEBUG_MODE - LogManager::getSingleton().stream(LML_TRIVIAL) << "*** Terrain Fragment Program: " - << ret->getName() << " ***\n" << ret->getSource() << "\n*** ***"; -#endif - - return ret; - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::generateVertexProgramSource( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - generateVpHeader(prof, terrain, tt, outStream); - - if (tt != LOW_LOD) - { - uint maxLayers = prof->getMaxLayers(terrain); - uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - - for (uint i = 0; i < numLayers; ++i) - generateVpLayer(prof, terrain, tt, i, outStream); - } - - generateVpFooter(prof, terrain, tt, outStream); - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::generateFragmentProgramSource( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - generateFpHeader(prof, terrain, tt, outStream); - - if (tt != LOW_LOD) - { - uint maxLayers = prof->getMaxLayers(terrain); - uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - - for (uint i = 0; i < numLayers; ++i) - generateFpLayer(prof, terrain, tt, i, outStream); - } - - generateFpFooter(prof, terrain, tt, outStream); - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::defaultVpParams( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog) - { - GpuProgramParametersSharedPtr params = prog->getDefaultParameters(); - params->setIgnoreMissingParams(true); - params->setNamedAutoConstant("worldMatrix", GpuProgramParameters::ACT_WORLD_MATRIX); - params->setNamedAutoConstant("viewProjMatrix", GpuProgramParameters::ACT_VIEWPROJ_MATRIX); - params->setNamedAutoConstant("lodMorph", GpuProgramParameters::ACT_CUSTOM, - Terrain::LOD_MORPH_CUSTOM_PARAM); - - if (prof->isShadowingEnabled(tt, terrain)) - { - uint numTextures = 1; - if (prof->getReceiveDynamicShadowsPSSM()) - { - numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); - } - for (uint i = 0; i < numTextures; ++i) - { - params->setNamedAutoConstant("texViewProjMatrix" + StringConverter::toString(i), - GpuProgramParameters::ACT_TEXTURE_VIEWPROJ_MATRIX, i); - if (prof->getReceiveDynamicShadowsDepth()) - { - //params->setNamedAutoConstant("depthRange" + StringConverter::toString(i), - //GpuProgramParameters::ACT_SHADOW_SCENE_DEPTH_RANGE, i); - } - } - } - - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::defaultFpParams( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog) - { - GpuProgramParametersSharedPtr params = prog->getDefaultParameters(); - params->setIgnoreMissingParams(true); - - params->setNamedAutoConstant("ambient", GpuProgramParameters::ACT_AMBIENT_LIGHT_COLOUR); - - for (int i=0; igetNumberOfLightsSupported(); ++i) - { - params->setNamedAutoConstant("lightPosObjSpace"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_POSITION_OBJECT_SPACE, i); - params->setNamedAutoConstant("lightDiffuseColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_DIFFUSE_COLOUR, i); - if (i > 0) - params->setNamedAutoConstant("lightAttenuation"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_ATTENUATION, i); - //params->setNamedAutoConstant("lightSpecularColour"+StringConverter::toString(i), GpuProgramParameters::ACT_LIGHT_SPECULAR_COLOUR, i); - } - - if (MWRender::RenderingManager::useMRT()) - params->setNamedAutoConstant("far", GpuProgramParameters::ACT_FAR_CLIP_DISTANCE); - - params->setNamedAutoConstant("eyePosObjSpace", GpuProgramParameters::ACT_CAMERA_POSITION_OBJECT_SPACE); - params->setNamedAutoConstant("fogColour", GpuProgramParameters::ACT_FOG_COLOUR); - params->setNamedAutoConstant("fogParams", GpuProgramParameters::ACT_FOG_PARAMS); - - if (prof->isShadowingEnabled(tt, terrain)) - { - params->setNamedConstant("shadowFar_fadeStart", Vector4(prof->mShadowFar, prof->mShadowFadeStart * prof->mShadowFar, 0, 0)); - uint numTextures = 1; - if (prof->getReceiveDynamicShadowsPSSM()) - { - PSSMShadowCameraSetup* pssm = prof->getReceiveDynamicShadowsPSSM(); - numTextures = pssm->getSplitCount(); - Vector4 splitPoints; - const PSSMShadowCameraSetup::SplitPointList& splitPointList = pssm->getSplitPoints(); - // Populate from split point 1, not 0, since split 0 isn't useful (usually 0) - for (uint i = 1; i < numTextures; ++i) - { - splitPoints[i-1] = splitPointList[i]; - } - params->setNamedConstant("pssmSplitPoints", splitPoints); - } - - if (prof->getReceiveDynamicShadowsDepth()) - { - size_t samplerOffset = (tt == HIGH_LOD) ? mShadowSamplerStartHi : mShadowSamplerStartLo; - for (uint i = 0; i < numTextures; ++i) - { - params->setNamedAutoConstant("inverseShadowmapSize" + StringConverter::toString(i), - GpuProgramParameters::ACT_INVERSE_TEXTURE_SIZE, i + samplerOffset); - } - } - } - - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::updateParams( - const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap) - { - Pass* p = mat->getTechnique(0)->getPass(0); - if (compositeMap) - { - updateVpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getVertexProgramParameters()); - updateFpParams(prof, terrain, RENDER_COMPOSITE_MAP, p->getFragmentProgramParameters()); - } - else - { - // high lod - updateVpParams(prof, terrain, HIGH_LOD, p->getVertexProgramParameters()); - updateFpParams(prof, terrain, HIGH_LOD, p->getFragmentProgramParameters()); - - if(prof->isCompositeMapEnabled()) - { - // low lod - p = mat->getTechnique(1)->getPass(0); - updateVpParams(prof, terrain, LOW_LOD, p->getVertexProgramParameters()); - updateFpParams(prof, terrain, LOW_LOD, p->getFragmentProgramParameters()); - } - } - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::updateVpParams( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params) - { - params->setIgnoreMissingParams(true); - uint maxLayers = prof->getMaxLayers(terrain); - uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - uint numUVMul = numLayers / 4; - if (numLayers % 4) - ++numUVMul; - for (uint i = 0; i < numUVMul; ++i) - { - Vector4 uvMul( - terrain->getLayerUVMultiplier(i * 4), - terrain->getLayerUVMultiplier(i * 4 + 1), - terrain->getLayerUVMultiplier(i * 4 + 2), - terrain->getLayerUVMultiplier(i * 4 + 3) - ); - params->setNamedConstant("uvMul" + StringConverter::toString(i), uvMul); - } - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::updateFpParams( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params) - { - params->setIgnoreMissingParams(true); - // TODO - parameterise this? - Vector4 scaleBiasSpecular(0.03, -0.04, 32, 1); - params->setNamedConstant("scaleBiasSpecular", scaleBiasSpecular); - - } - //--------------------------------------------------------------------- - String TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::getChannel(uint idx) - { - uint rem = idx % 4; - switch(rem) - { - case 0: - default: - return "r"; - case 1: - return "g"; - case 2: - return "b"; - case 3: - return "a"; - }; - } - //--------------------------------------------------------------------- - String TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::getVertexProgramName( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - String progName = terrain->getMaterialName() + "/sm2/vp"; - - switch(tt) - { - case HIGH_LOD: - progName += "/hlod"; - break; - case LOW_LOD: - progName += "/llod"; - break; - case RENDER_COMPOSITE_MAP: - progName += "/comp"; - break; - } - - return progName; - - } - //--------------------------------------------------------------------- - String TerrainMaterialGeneratorB::SM2Profile::ShaderHelper::getFragmentProgramName( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - - String progName = terrain->getMaterialName() + "/sm2/fp"; - - switch(tt) - { - case HIGH_LOD: - progName += "/hlod"; - break; - case LOW_LOD: - progName += "/llod"; - break; - case RENDER_COMPOSITE_MAP: - progName += "/comp"; - break; - } - - return progName; - } - //--------------------------------------------------------------------- - //--------------------------------------------------------------------- - HighLevelGpuProgramPtr - TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::createVertexProgram( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - String progName = getVertexProgramName(prof, terrain, tt); - HighLevelGpuProgramPtr ret = mgr.getByName(progName); - if (ret.isNull()) - { - ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_VERTEX_PROGRAM); - } - else - { - ret->unload(); - } - - ret->setParameter("profiles", "vs_3_0 vs_2_0 vp40 arbvp1"); - ret->setParameter("entry_point", "main_vp"); - - return ret; - - } - //--------------------------------------------------------------------- - HighLevelGpuProgramPtr - TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::createFragmentProgram( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - String progName = getFragmentProgramName(prof, terrain, tt); - - HighLevelGpuProgramPtr ret = mgr.getByName(progName); - if (ret.isNull()) - { - ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "cg", GPT_FRAGMENT_PROGRAM); - } - else - { - ret->unload(); - } - - ret->setParameter("profiles", "ps_3_0 ps_2_x fp40 arbfp1"); - ret->setParameter("entry_point", "main_fp"); - - return ret; - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpHeader( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - outStream << - "void main_vp(\n" - "float4 pos : POSITION,\n" - "float2 uv : TEXCOORD0,\n"; - if (tt != RENDER_COMPOSITE_MAP) - outStream << "float2 delta : TEXCOORD1,\n"; // lodDelta, lodThreshold - - outStream << - "uniform float4x4 worldMatrix,\n" - "uniform float4x4 viewProjMatrix,\n" - "uniform float2 lodMorph,\n"; // morph amount, morph LOD target - - // uv multipliers - uint maxLayers = prof->getMaxLayers(terrain); - uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - uint numUVMultipliers = (numLayers / 4); - if (numLayers % 4) - ++numUVMultipliers; - for (uint i = 0; i < numUVMultipliers; ++i) - outStream << "uniform float4 uvMul" << i << ", \n"; - - outStream << - "out float4 oPos : POSITION,\n" - "out float4 oPosObj : TEXCOORD0 \n"; - - uint texCoordSet = 1; - outStream << - ", out float4 oUVMisc : COLOR0 // xy = uv, z = camDepth\n"; - - // layer UV's premultiplied, packed as xy/zw - uint numUVSets = numLayers / 2; - if (numLayers % 2) - ++numUVSets; - if (tt != LOW_LOD) - { - for (uint i = 0; i < numUVSets; ++i) - { - outStream << - ", out float4 oUV" << i << " : TEXCOORD" << texCoordSet++ << "\n"; - } - } - - if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP) - { - outStream << ", out float2 lodInfo : TEXCOORD" << texCoordSet++ << "\n"; - } - - if (prof->isShadowingEnabled(tt, terrain)) - { - texCoordSet = generateVpDynamicShadowsParams(texCoordSet, prof, terrain, tt, outStream); - } - - // check we haven't exceeded texture coordinates - if (texCoordSet > 8) - { - OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, - "Requested options require too many texture coordinate sets! Try reducing the number of layers. requested: " + StringConverter::toString(texCoordSet), - __FUNCTION__); - } - - outStream << - ")\n" - "{\n" - " float4 worldPos = mul(worldMatrix, pos);\n" - " oPosObj = pos;\n"; - - if (tt != RENDER_COMPOSITE_MAP) - { - // determine whether to apply the LOD morph to this vertex - // we store the deltas against all vertices so we only want to apply - // the morph to the ones which would disappear. The target LOD which is - // being morphed to is stored in lodMorph.y, and the LOD at which - // the vertex should be morphed is stored in uv.w. If we subtract - // the former from the latter, and arrange to only morph if the - // result is negative (it will only be -1 in fact, since after that - // the vertex will never be indexed), we will achieve our aim. - // sign(vertexLOD - targetLOD) == -1 is to morph - outStream << - " float toMorph = -min(0, sign(delta.y - lodMorph.y));\n"; - // this will either be 1 (morph) or 0 (don't morph) - if (prof->getParent()->getDebugLevel()) - { - // x == LOD level (-1 since value is target level, we want to display actual) - outStream << "lodInfo.x = (lodMorph.y - 1) / " << terrain->getNumLodLevels() << ";\n"; - // y == LOD morph - outStream << "lodInfo.y = toMorph * lodMorph.x;\n"; - } - - // morph - switch (terrain->getAlignment()) - { - case Terrain::ALIGN_X_Y: - outStream << " worldPos.z += delta.x * toMorph * lodMorph.x;\n"; - break; - case Terrain::ALIGN_X_Z: - outStream << " worldPos.y += delta.x * toMorph * lodMorph.x;\n"; - break; - case Terrain::ALIGN_Y_Z: - outStream << " worldPos.x += delta.x * toMorph * lodMorph.x;\n"; - break; - }; - } - - - // generate UVs - if (tt != LOW_LOD) - { - for (uint i = 0; i < numUVSets; ++i) - { - uint layer = i * 2; - uint uvMulIdx = layer / 4; - - outStream << - " oUV" << i << ".xy = " << " uv.xy * uvMul" << uvMulIdx << "." << getChannel(layer) << ";\n"; - outStream << - " oUV" << i << ".zw = " << " uv.xy * uvMul" << uvMulIdx << "." << getChannel(layer+1) << ";\n"; - - } - - } - - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpHeader( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - - // Main header - outStream << - // helpers - "float4 expand(float4 v)\n" - "{ \n" - " return v * 2 - 1;\n" - "}\n\n\n"; - - if (prof->isShadowingEnabled(tt, terrain)) - generateFpDynamicShadowsHelpers(prof, terrain, tt, outStream); - - - outStream << - "void main_fp(\n" - "float4 position : TEXCOORD0,\n"; - - uint texCoordSet = 1; - outStream << - "float4 uvMisc : COLOR0,\n"; - - // UV's premultiplied, packed as xy/zw - uint maxLayers = prof->getMaxLayers(terrain); - uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount()); - uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - uint numUVSets = numLayers / 2; - if (numLayers % 2) - ++numUVSets; - if (tt != LOW_LOD) - { - for (uint i = 0; i < numUVSets; ++i) - { - outStream << - "float4 layerUV" << i << " : TEXCOORD" << texCoordSet++ << ", \n"; - } - - } - if (prof->getParent()->getDebugLevel() && tt != RENDER_COMPOSITE_MAP) - { - outStream << "float2 lodInfo : TEXCOORD" << texCoordSet++ << ", \n"; - } - - bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; - if (fog) - { - outStream << - "uniform float4 fogParams, \n" - "uniform float3 fogColour, \n"; - } - - uint currentSamplerIdx = 0; - - outStream << - // Only 1 light supported in this version - // deferred shading profile / generator later, ok? :) - "uniform float3 ambient,\n"; - - - for (int i=0; igetNumberOfLightsSupported(); ++i) - { - outStream << - "uniform float4 lightPosObjSpace"< 0) - outStream << - "uniform float4 lightAttenuation"<isGlobalColourMapEnabled()) - { - outStream << ", uniform sampler2D globalColourMap : register(s" - << currentSamplerIdx++ << ")\n"; - } - if (prof->isLightmapEnabled()) - { - outStream << ", uniform sampler2D lightMap : register(s" - << currentSamplerIdx++ << ")\n"; - } - // Blend textures - sampler definitions - for (uint i = 0; i < numBlendTextures; ++i) - { - outStream << ", uniform sampler2D blendTex" << i - << " : register(s" << currentSamplerIdx++ << ")\n"; - } - - // Layer textures - sampler definitions & UV multipliers - for (uint i = 0; i < numLayers; ++i) - { - outStream << ", uniform sampler2D difftex" << i - << " : register(s" << currentSamplerIdx++ << ")\n"; - - if (prof->mLayerNormalMappingEnabled || prof->mLayerParallaxMappingEnabled) - outStream << ", uniform sampler2D normtex" << i - << " : register(s" << currentSamplerIdx++ << ")\n"; - } - } - - if (prof->isShadowingEnabled(tt, terrain)) - { - generateFpDynamicShadowsParams(&texCoordSet, ¤tSamplerIdx, prof, terrain, tt, outStream); - } - - // check we haven't exceeded samplers - if (currentSamplerIdx > 16) - { - OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, - "Requested options require too many texture samplers! Try reducing the number of layers.", - __FUNCTION__); - } - - if (MWRender::RenderingManager::useMRT()) outStream << - " , out float4 oColor : COLOR \n" - " , out float4 oColor1 : COLOR1 \n" - " , uniform float far \n"; - else outStream << - " , out float4 oColor : COLOR \n"; - - outStream << - ")\n" - "{\n" - " float4 outputCol;\n" - " float shadow = 1.0;\n" - " float2 uv = uvMisc.xy;\n" - // base colour - " outputCol = float4(0,0,0,1);\n"; - - if (tt != LOW_LOD) - { - outStream << - // global normal - " float3 normal = expand(tex2D(globalNormal, uv)).rgb;\n"; - - // not needed anymore apparently - //" normal = float3(normal.x, normal.z, -normal.y); \n"; // convert Ogre to MW coordinate system - - } - - for (int i=0; igetNumberOfLightsSupported(); ++i) - outStream << - " float3 lightDir"<isLayerNormalMappingEnabled()) - { - // derive the tangent space basis - // we do this in the pixel shader because we don't have per-vertex normals - // because of the LOD, we use a normal map - // tangent is always +x or -z in object space depending on alignment - switch(terrain->getAlignment()) - { - case Terrain::ALIGN_X_Y: - case Terrain::ALIGN_X_Z: - outStream << " float3 tangent = float3(1, 0, 0);\n"; - break; - case Terrain::ALIGN_Y_Z: - outStream << " float3 tangent = float3(0, 0, -1);\n"; - break; - }; - - outStream << " float3 binormal = normalize(cross(tangent, normal));\n"; - // note, now we need to re-cross to derive tangent again because it wasn't orthonormal - outStream << " tangent = normalize(cross(normal, binormal));\n"; - // derive final matrix - outStream << " float3x3 TBN = float3x3(tangent, binormal, normal);\n"; - - // set up lighting result placeholders for interpolation - outStream << " float4 litRes, litResLayer;\n"; - outStream << " float3 TSlightDir, TSeyeDir, TShalfAngle, TSnormal;\n"; - if (prof->isLayerParallaxMappingEnabled()) - outStream << " float displacement;\n"; - // move - outStream << " TSlightDir = normalize(mul(TBN, lightDir));\n"; - outStream << " TSeyeDir = normalize(mul(TBN, eyeDir));\n"; - - } - else - { - if (prof->getNumberOfLightsSupported() > 1) - outStream << "float d; \n" - "float attn; \n"; - - outStream << - " eyeDir = normalize(eyeDir); \n"; - - // simple per-pixel lighting with no normal mapping - for (int i=0; igetNumberOfLightsSupported(); ++i) - { - outStream << - " float4 litRes"< 0) - outStream << - // pre-multiply light color with attenuation factor - "d = length( lightDir"<_isSM3Available()) - outStream << " if (" << blendWeightStr << " > 0.0003)\n { \n"; - - - // generate UV - outStream << " float2 uv" << layer << " = layerUV" << uvIdx << uvChannels << ";\n"; - - // calculate lighting here if normal mapping - if (prof->isLayerNormalMappingEnabled()) - { - if (prof->isLayerParallaxMappingEnabled() && tt != RENDER_COMPOSITE_MAP) - { - // modify UV - note we have to sample an extra time - outStream << " displacement = tex2D(normtex" << layer << ", uv" << layer << ").a\n" - " * scaleBiasSpecular.x + scaleBiasSpecular.y;\n"; - outStream << " uv" << layer << " += TSeyeDir.xy * displacement;\n"; - } - - // access TS normal map - outStream << " TSnormal = expand(tex2D(normtex" << layer << ", uv" << layer << ")).rgb;\n"; - outStream << " TShalfAngle = normalize(TSlightDir + TSeyeDir);\n"; - outStream << " litResLayer = lit(dot(TSlightDir, TSnormal), dot(TShalfAngle, TSnormal), scaleBiasSpecular.z);\n"; - if (!layer) - outStream << " litRes = litResLayer;\n"; - else - outStream << " litRes = lerp(litRes, litResLayer, " << blendWeightStr << ");\n"; - - } - - // sample diffuse texture - outStream << " float4 diffuseSpecTex" << layer - << " = tex2D(difftex" << layer << ", uv" << layer << ");\n"; - - // apply to common - if (!layer) - { - outStream << " diffuse = diffuseSpecTex0.rgb;\n"; - if (prof->isLayerSpecularMappingEnabled()) - outStream << " specular = diffuseSpecTex0.a;\n"; - } - else - { - outStream << " diffuse = lerp(diffuse, diffuseSpecTex" << layer - << ".rgb, " << blendWeightStr << ");\n"; - if (prof->isLayerSpecularMappingEnabled()) - outStream << " specular = lerp(specular, diffuseSpecTex" << layer - << ".a, " << blendWeightStr << ");\n"; - - } - - // End early-out - // Disable - causing some issues even when trying to force the use of texldd - - // comment by scrawl: - // on a NVIDIA card in opengl mode, didn't produce any problems, - // while increasing FPS from 170 to 185 (!!!) in the same area - // so let's try this out - if something does cause problems for - // someone else (with a different card / renderer) we can just - // add a vendor-specific check here - if (layer && prof->_isSM3Available()) - outStream << " } // early-out blend value\n"; - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpFooter( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - - outStream << - " oPos = mul(viewProjMatrix, worldPos);\n" - " oUVMisc.xy = uv.xy;\n"; - - outStream << - " // pass cam depth\n" - " oPosObj.w = oPos.z;\n"; - - if (prof->isShadowingEnabled(tt, terrain)) - generateVpDynamicShadows(prof, terrain, tt, outStream); - - outStream << - "}\n"; - - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpFooter( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - - if (tt == LOW_LOD) - { - if (prof->isShadowingEnabled(tt, terrain)) - { - generateFpDynamicShadows(prof, terrain, tt, outStream); - outStream << - " outputCol.rgb = diffuse * rtshadow;\n"; - } - else - { - outStream << - " outputCol.rgb = diffuse;\n"; - } - } - else - { - if (prof->isGlobalColourMapEnabled()) - { - // sample colour map and apply to diffuse - outStream << " diffuse *= tex2D(globalColourMap, uv).rgb;\n"; - } - if (prof->isLightmapEnabled()) - { - // sample lightmap - outStream << " shadow = tex2D(lightMap, uv).r;\n"; - } - - if (prof->isShadowingEnabled(tt, terrain)) - { - generateFpDynamicShadows(prof, terrain, tt, outStream); - } - - outStream << " outputCol.rgb += ambient * diffuse; \n"; - - // diffuse lighting - for (int i=0; igetNumberOfLightsSupported(); ++i) - { - // shadows only for first light (directional) - if (i==0) - outStream << " outputCol.rgb += litRes"<isLayerSpecularMappingEnabled()) - outStream << " specular = 0.0;\n"; - - if (tt == RENDER_COMPOSITE_MAP) - { - // Lighting embedded in alpha - outStream << - " outputCol.a = shadow;\n"; - - } - else - { - // Apply specular - //outStream << " outputCol.rgb += litRes.z * lightSpecularColour * specular * shadow;\n"; - - if (prof->getParent()->getDebugLevel()) - { - outStream << " outputCol.rg += lodInfo.xy;\n"; - } - } - } - - bool fog = terrain->getSceneManager()->getFogMode() != FOG_NONE && tt != RENDER_COMPOSITE_MAP; - if (fog) - { - if (terrain->getSceneManager()->getFogMode() == FOG_LINEAR) - { - outStream << - " float fogVal = saturate((position.w - fogParams.y) * fogParams.w);\n"; - } - else - { - outStream << - " float fogVal = saturate(1 / (exp(position.w * fogParams.x)));\n"; - } - outStream << " outputCol.rgb = lerp(outputCol.rgb, fogColour, fogVal);\n"; - } - - // Final return - outStream << " oColor = outputCol;\n"; - - if (MWRender::RenderingManager::useMRT()) outStream << - " oColor1 = float4(position.w / far, 0, 0, 1); \n"; - - outStream - << "}\n"; - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadowsHelpers( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - // TODO make filtering configurable - outStream << - "// Simple PCF \n" - "// Number of samples in one dimension (square for total samples) \n" - "#define NUM_SHADOW_SAMPLES_1D 1.0 \n" - "#define SHADOW_FILTER_SCALE 1 \n" - - "#define SHADOW_SAMPLES NUM_SHADOW_SAMPLES_1D*NUM_SHADOW_SAMPLES_1D \n" - - "float4 offsetSample(float4 uv, float2 offset, float invMapSize) \n" - "{ \n" - " return float4(uv.xy + offset * invMapSize * uv.w, uv.z, uv.w); \n" - "} \n"; - - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << - "float calcDepthShadow(sampler2D shadowMap, float4 shadowMapPos, float2 offset) \n" - " { \n" - " shadowMapPos = shadowMapPos / shadowMapPos.w; \n" - " float2 uv = shadowMapPos.xy; \n" - " float3 o = float3(offset, -offset.x) * 0.3f; \n" - " // Note: We using 2x2 PCF. Good enough and is alot faster. \n" - " float c = (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.xy).r) ? 1 : 0; // top left \n" - " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.xy).r) ? 1 : 0; // bottom right \n" - " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy + o.zy).r) ? 1 : 0; // bottom left \n" - " c += (shadowMapPos.z <= tex2D(shadowMap, uv.xy - o.zy).r) ? 1 : 0; // top right \n" - " return c / 4; \n" - " } \n"; - } - else - { - outStream << - "float calcSimpleShadow(sampler2D shadowMap, float4 shadowMapPos) \n" - "{ \n" - " return tex2Dproj(shadowMap, shadowMapPos).x; \n" - "} \n"; - - } - - if (prof->getReceiveDynamicShadowsPSSM()) - { - uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); - - - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << - "float calcPSSMDepthShadow("; - } - else - { - outStream << - "float calcPSSMSimpleShadow("; - } - - outStream << "\n "; - for (uint i = 0; i < numTextures; ++i) - outStream << "sampler2D shadowMap" << i << ", "; - outStream << "\n "; - for (uint i = 0; i < numTextures; ++i) - outStream << "float4 lsPos" << i << ", "; - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << "\n "; - for (uint i = 0; i < numTextures; ++i) - outStream << "float2 invShadowmapSize" << i << ", "; - } - outStream << "\n" - " float4 pssmSplitPoints, float camDepth) \n" - "{ \n" - " float shadow; \n" - " // calculate shadow \n"; - - for (uint i = 0; i < numTextures; ++i) - { - if (!i) - outStream << " if (camDepth <= pssmSplitPoints." << ShaderHelper::getChannel(i) << ") \n"; - else if (i < numTextures - 1) - outStream << " else if (camDepth <= pssmSplitPoints." << ShaderHelper::getChannel(i) << ") \n"; - else - outStream << " else \n"; - - outStream << - " { \n"; - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << - " shadow = calcDepthShadow(shadowMap" << i << ", lsPos" << i << ", invShadowmapSize" << i << ".xy); \n"; - } - else - { - outStream << - " shadow = calcSimpleShadow(shadowMap" << i << ", lsPos" << i << "); \n"; - } - outStream << - " } \n"; - - } - - outStream << - " return shadow; \n" - "} \n\n\n"; - } - - - } - //--------------------------------------------------------------------- - uint TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpDynamicShadowsParams( - uint texCoord, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - // out semantics & params - uint numTextures = 1; - if (prof->getReceiveDynamicShadowsPSSM()) - { - numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); - } - for (uint i = 0; i < numTextures; ++i) - { - outStream << - ", out float4 oLightSpacePos" << i << " : TEXCOORD" << texCoord++ << " \n" << - ", uniform float4x4 texViewProjMatrix" << i << " \n"; - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << - ", uniform float4 depthRange" << i << " // x = min, y = max, z = range, w = 1/range \n"; - } - } - - return texCoord; - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateVpDynamicShadows( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - uint numTextures = 1; - if (prof->getReceiveDynamicShadowsPSSM()) - { - numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); - } - - // Calculate the position of vertex in light space - for (uint i = 0; i < numTextures; ++i) - { - outStream << - " oLightSpacePos" << i << " = mul(texViewProjMatrix" << i << ", worldPos); \n"; - if (prof->getReceiveDynamicShadowsDepth()) - { - // make linear - //outStream << - // "oLightSpacePos" << i << ".z = (oLightSpacePos" << i << ".z - depthRange" << i << ".x) * depthRange" << i << ".w;\n"; - - } - } - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadowsParams( - uint* texCoord, uint* sampler, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - if (tt == HIGH_LOD) - mShadowSamplerStartHi = *sampler; - else if (tt == LOW_LOD) - mShadowSamplerStartLo = *sampler; - - // in semantics & params - uint numTextures = 1; - outStream << - ", uniform float4 shadowFar_fadeStart \n"; - if (prof->getReceiveDynamicShadowsPSSM()) - { - numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); - outStream << - ", uniform float4 pssmSplitPoints \n"; - } - for (uint i = 0; i < numTextures; ++i) - { - outStream << - ", float4 lightSpacePos" << i << " : TEXCOORD" << *texCoord << " \n" << - ", uniform sampler2D shadowMap" << i << " : register(s" << *sampler << ") \n"; - *sampler = *sampler + 1; - *texCoord = *texCoord + 1; - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << - ", uniform float4 inverseShadowmapSize" << i << " \n"; - } - } - - } - //--------------------------------------------------------------------- - void TerrainMaterialGeneratorB::SM2Profile::ShaderHelperCg::generateFpDynamicShadows( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) - { - if (prof->getReceiveDynamicShadowsPSSM()) - { - uint numTextures = prof->getReceiveDynamicShadowsPSSM()->getSplitCount(); - outStream << - " float camDepth = position.w;\n"; - - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << - " float rtshadow = calcPSSMDepthShadow("; - } - else - { - outStream << - " float rtshadow = calcPSSMSimpleShadow("; - } - for (uint i = 0; i < numTextures; ++i) - outStream << "shadowMap" << i << ", "; - outStream << "\n "; - - for (uint i = 0; i < numTextures; ++i) - outStream << "lightSpacePos" << i << ", "; - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << "\n "; - for (uint i = 0; i < numTextures; ++i) - outStream << "inverseShadowmapSize" << i << ".xy, "; - } - outStream << "\n" << - " pssmSplitPoints, camDepth);\n"; - - } - else - { - if (prof->getReceiveDynamicShadowsDepth()) - { - outStream << - " float rtshadow = calcDepthShadow(shadowMap0, lightSpacePos0, inverseShadowmapSize0.xy);"; - } - else - { - outStream << - " float rtshadow = calcSimpleShadow(shadowMap0, lightSpacePos0);"; - } - } - - outStream << - " float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; \n" - " float fade = 1-((position.w - shadowFar_fadeStart.y) / fadeRange); \n" - " rtshadow = (position.w > shadowFar_fadeStart.x) ? 1 : ((position.w > shadowFar_fadeStart.y) ? 1-((1-rtshadow)*fade) : rtshadow); \n" - " rtshadow = (1-(1-rtshadow)*0.6); \n" // make the shadow a little less intensive - " shadow = min(shadow, rtshadow);\n"; - - } - //--------------------------------------------------------------------- - //--------------------------------------------------------------------- - HighLevelGpuProgramPtr - TerrainMaterialGeneratorB::SM2Profile::ShaderHelperHLSL::createVertexProgram( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - String progName = getVertexProgramName(prof, terrain, tt); - - HighLevelGpuProgramPtr ret = mgr.getByName(progName); - if (ret.isNull()) - { - ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "hlsl", GPT_VERTEX_PROGRAM); - } - else - { - ret->unload(); - } - - if (prof->_isSM3Available()) - ret->setParameter("target", "vs_3_0"); - else - ret->setParameter("target", "vs_2_0"); - ret->setParameter("entry_point", "main_vp"); - - return ret; - - } - //--------------------------------------------------------------------- - HighLevelGpuProgramPtr - TerrainMaterialGeneratorB::SM2Profile::ShaderHelperHLSL::createFragmentProgram( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - String progName = getFragmentProgramName(prof, terrain, tt); - - - HighLevelGpuProgramPtr ret = mgr.getByName(progName); - if (ret.isNull()) - { - ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "hlsl", GPT_FRAGMENT_PROGRAM); - } - else - { - ret->unload(); - } - - if (prof->_isSM3Available()) - ret->setParameter("target", "ps_3_0"); - else - ret->setParameter("target", "ps_2_x"); - ret->setParameter("entry_point", "main_fp"); - - return ret; - - } - //--------------------------------------------------------------------- - //--------------------------------------------------------------------- - HighLevelGpuProgramPtr - TerrainMaterialGeneratorB::SM2Profile::ShaderHelperGLSL::createVertexProgram( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - String progName = getVertexProgramName(prof, terrain, tt); - - switch(tt) - { - case HIGH_LOD: - progName += "/hlod"; - break; - case LOW_LOD: - progName += "/llod"; - break; - case RENDER_COMPOSITE_MAP: - progName += "/comp"; - break; - } - - HighLevelGpuProgramPtr ret = mgr.getByName(progName); - if (ret.isNull()) - { - ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "glsl", GPT_VERTEX_PROGRAM); - } - else - { - ret->unload(); - } - - return ret; - - } - //--------------------------------------------------------------------- - HighLevelGpuProgramPtr - TerrainMaterialGeneratorB::SM2Profile::ShaderHelperGLSL::createFragmentProgram( - const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) - { - HighLevelGpuProgramManager& mgr = HighLevelGpuProgramManager::getSingleton(); - String progName = getFragmentProgramName(prof, terrain, tt); - - HighLevelGpuProgramPtr ret = mgr.getByName(progName); - if (ret.isNull()) - { - ret = mgr.createProgram(progName, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "glsl", GPT_FRAGMENT_PROGRAM); - } - else - { - ret->unload(); - } - - return ret; - - } + void TerrainMaterial::Profile::setGlobalColourMap (Ogre::Terrain* terrain, const std::string& name) + { + sh::Factory::getInstance ().setTextureAlias (terrain->getMaterialName () + "_colourMap", name); + } + + Ogre::MaterialPtr TerrainMaterial::Profile::generateForCompositeMap(const Ogre::Terrain* terrain) + { + throw std::runtime_error ("composite map not supported"); + } + + Ogre::uint8 TerrainMaterial::Profile::getMaxLayers(const Ogre::Terrain* terrain) const + { + // count the texture units free + Ogre::uint8 freeTextureUnits = 16; + // normalmap + --freeTextureUnits; + // colourmap + --freeTextureUnits; + freeTextureUnits -= 3; // shadow PSSM + + --freeTextureUnits; // caustics + + // each layer needs 1.25 units (1xdiffusespec, 0.25xblend) + return static_cast(freeTextureUnits / (1.25f)); + } + + void TerrainMaterial::Profile::updateParams(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain) + { + } + + void TerrainMaterial::Profile::updateParamsForCompositeMap(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain) + { + } + + void TerrainMaterial::Profile::requestOptions(Ogre::Terrain* terrain) + { + terrain->_setMorphRequired(true); + terrain->_setNormalMapRequired(true); // global normal map + terrain->_setLightMapRequired(false); + terrain->_setCompositeMapRequired(false); + } } diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index e94e20b7e..3e31b2a58 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -26,246 +26,59 @@ THE SOFTWARE. ----------------------------------------------------------------------------- */ -#ifndef __Ogre_TerrainMaterialGeneratorB_H__ -#define __Ogre_TerrainMaterialGeneratorB_H__ +#ifndef MWRENDER_TERRAINMATERIAL_H +#define MWRENDER_TERRAINMATERIAL_H #include "OgreTerrainPrerequisites.h" #include "OgreTerrainMaterialGenerator.h" #include "OgreGpuProgramParams.h" -namespace Ogre +namespace sh { - class PSSMShadowCameraSetup; + class MaterialInstance; +} - /** \addtogroup Optional Components - * @{ - */ - /** \addtogroup Terrain - * Some details on the terrain component - * @{ - */ +namespace MWRender +{ + class TerrainMaterial : public Ogre::TerrainMaterialGenerator + { + public: - /** A TerrainMaterialGenerator which can cope with normal mapped, specular mapped - terrain. - @note Requires the Cg plugin to render correctly - */ - class TerrainMaterialGeneratorB : public TerrainMaterialGenerator - { - public: - TerrainMaterialGeneratorB(); - ~TerrainMaterialGeneratorB(); + class Profile : public Ogre::TerrainMaterialGenerator::Profile + { + public: + Profile(Ogre::TerrainMaterialGenerator* parent, const Ogre::String& name, const Ogre::String& desc); + virtual ~Profile(); - /** Shader model 2 profile target. - */ - class SM2Profile : public TerrainMaterialGenerator::Profile - { - public: - SM2Profile(TerrainMaterialGenerator* parent, const String& name, const String& desc); - ~SM2Profile(); + virtual bool isVertexCompressionSupported() const { return false; } - bool isVertexCompressionSupported() const {return false;} - - MaterialPtr generate(const Terrain* terrain); - MaterialPtr generateForCompositeMap(const Terrain* terrain); - uint8 getMaxLayers(const Terrain* terrain) const; - void updateParams(const MaterialPtr& mat, const Terrain* terrain); - void updateParamsForCompositeMap(const MaterialPtr& mat, const Terrain* terrain); - void requestOptions(Terrain* terrain); + virtual Ogre::MaterialPtr generate(const Ogre::Terrain* terrain); - void setShadowFar(float far); - void setShadowFadeStart(float fadestart); + virtual Ogre::MaterialPtr generateForCompositeMap(const Ogre::Terrain* terrain); - /** Whether to support normal mapping per layer in the shader (default true). - */ - bool isLayerNormalMappingEnabled() const { return mLayerNormalMappingEnabled; } - /** Whether to support normal mapping per layer in the shader (default true). - */ - void setLayerNormalMappingEnabled(bool enabled); - /** Whether to support parallax mapping per layer in the shader (default true). - */ - bool isLayerParallaxMappingEnabled() const { return mLayerParallaxMappingEnabled; } - /** Whether to support parallax mapping per layer in the shader (default true). - */ - void setLayerParallaxMappingEnabled(bool enabled); - /** Whether to support specular mapping per layer in the shader (default true). - */ - bool isLayerSpecularMappingEnabled() const { return mLayerSpecularMappingEnabled; } - /** Whether to support specular mapping per layer in the shader (default true). - */ - void setLayerSpecularMappingEnabled(bool enabled); - /** Whether to support a global colour map over the terrain in the shader, - if it's present (default true). - */ - bool isGlobalColourMapEnabled() const { return mGlobalColourMapEnabled; } - /** Whether to support a global colour map over the terrain in the shader, - if it's present (default true). - */ - void setGlobalColourMapEnabled(bool enabled); - /** Whether to support a light map over the terrain in the shader, - if it's present (default true). - */ - bool isLightmapEnabled() const { return mLightmapEnabled; } - /** Whether to support a light map over the terrain in the shader, - if it's present (default true). - */ - void setLightmapEnabled(bool enabled); - /** Whether to use the composite map to provide a lower LOD technique - in the distance (default true). - */ - bool isCompositeMapEnabled() const { return mCompositeMapEnabled; } - /** Whether to use the composite map to provide a lower LOD technique - in the distance (default true). - */ - void setCompositeMapEnabled(bool enabled); - /** Whether to support dynamic texture shadows received from other - objects, on the terrain (default true). - */ - bool getReceiveDynamicShadowsEnabled() const { return mReceiveDynamicShadows; } - /** Whether to support dynamic texture shadows received from other - objects, on the terrain (default true). - */ - void setReceiveDynamicShadowsEnabled(bool enabled); + virtual Ogre::uint8 getMaxLayers(const Ogre::Terrain* terrain) const; - /** Whether to use PSSM support dynamic texture shadows, and if so the - settings to use (default 0). - */ - void setReceiveDynamicShadowsPSSM(PSSMShadowCameraSetup* pssmSettings); - /** Whether to use PSSM support dynamic texture shadows, and if so the - settings to use (default 0). - */ - PSSMShadowCameraSetup* getReceiveDynamicShadowsPSSM() const { return mPSSM; } - /** Whether to use depth shadows (default false). - */ - void setReceiveDynamicShadowsDepth(bool enabled); - /** Whether to use depth shadows (default false). - */ - bool getReceiveDynamicShadowsDepth() const { return mDepthShadows; } - /** Whether to use shadows on low LOD material rendering (when using composite map) (default false). - */ - void setReceiveDynamicShadowsLowLod(bool enabled); - /** Whether to use shadows on low LOD material rendering (when using composite map) (default false). - */ - bool getReceiveDynamicShadowsLowLod() const { return mLowLodShadows; } + virtual void updateParams(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain); - int getNumberOfLightsSupported() const; + virtual void updateParamsForCompositeMap(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain); - /// Internal - bool _isSM3Available() const { return mSM3Available; } - - protected: + virtual void requestOptions(Ogre::Terrain* terrain); - enum TechniqueType - { - HIGH_LOD, - LOW_LOD, - RENDER_COMPOSITE_MAP - }; - void addTechnique(const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt); + void setGlobalColourMapEnabled(bool enabled); + void setGlobalColourMap (Ogre::Terrain* terrain, const std::string& name); - /// Interface definition for helper class to generate shaders - class ShaderHelper : public TerrainAlloc - { - public: - ShaderHelper() : mShadowSamplerStartHi(0), mShadowSamplerStartLo(0) {} - virtual ~ShaderHelper() {} - virtual HighLevelGpuProgramPtr generateVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - virtual HighLevelGpuProgramPtr generateFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - virtual void updateParams(const SM2Profile* prof, const MaterialPtr& mat, const Terrain* terrain, bool compositeMap); - protected: - virtual String getVertexProgramName(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - virtual String getFragmentProgramName(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - virtual HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) = 0; - virtual HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt) = 0; - virtual void generateVertexProgramSource(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - virtual void generateFragmentProgramSource(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - virtual void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0; - virtual void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0; - virtual void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) = 0; - virtual void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) = 0; - virtual void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0; - virtual void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) = 0; - virtual void defaultVpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog); - virtual void defaultFpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const HighLevelGpuProgramPtr& prog); - virtual void updateVpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params); - virtual void updateFpParams(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, const GpuProgramParametersSharedPtr& params); - static String getChannel(uint idx); + private: + sh::MaterialInstance* mMaterial; - size_t mShadowSamplerStartHi; - size_t mShadowSamplerStartLo; + bool mGlobalColourMap; - }; - - /// Utility class to help with generating shaders for Cg / HLSL. - class ShaderHelperCg : public ShaderHelper - { - protected: - HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream); - void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream); - void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - uint generateVpDynamicShadowsParams(uint texCoordStart, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - void generateVpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - void generateFpDynamicShadowsHelpers(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - void generateFpDynamicShadowsParams(uint* texCoord, uint* sampler, const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - void generateFpDynamicShadows(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream); - }; - - class ShaderHelperHLSL : public ShaderHelperCg - { - protected: - HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - }; - - /// Utility class to help with generating shaders for GLSL. - class ShaderHelperGLSL : public ShaderHelper - { - protected: - HighLevelGpuProgramPtr createVertexProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - HighLevelGpuProgramPtr createFragmentProgram(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt); - void generateVpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {} - void generateFpHeader(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {} - void generateVpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) {} - void generateFpLayer(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, uint layer, StringUtil::StrStreamType& outStream) {} - void generateVpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {} - void generateFpFooter(const SM2Profile* prof, const Terrain* terrain, TechniqueType tt, StringUtil::StrStreamType& outStream) {} - }; - - ShaderHelper* mShaderGen; - bool mLayerNormalMappingEnabled; - bool mLayerParallaxMappingEnabled; - bool mLayerSpecularMappingEnabled; - bool mGlobalColourMapEnabled; - bool mLightmapEnabled; - bool mCompositeMapEnabled; - bool mReceiveDynamicShadows; - PSSMShadowCameraSetup* mPSSM; - bool mDepthShadows; - bool mLowLodShadows; - bool mSM3Available; - float mShadowFar; - float mShadowFadeStart; - - bool isShadowingEnabled(TechniqueType tt, const Terrain* terrain) const; - - }; - - - - - }; - - - - /** @} */ - /** @} */ + }; + TerrainMaterial(); + }; } + #endif diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index dc9e1fbee..d5b93b7cb 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,9 +1,27 @@ #include "water.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "sky.hpp" #include "renderingmanager.hpp" #include "compositors.hpp" +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + using namespace Ogre; namespace MWRender @@ -13,10 +31,14 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mCamera (camera), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mReflectionTarget(0), mActive(1), mToggled(1), - mReflectionRenderActive(false), mRendering(rend) + mReflectionRenderActive(false), mRendering(rend), + mOldFarClip(0), mOldFarClip2(0), + mWaterTimer(0.f) { mSky = rend->getSkyManager(); + mMaterial = MaterialManager::getSingleton().getByName("Water"); + mTop = cell->water; mIsUnderwater = false; @@ -31,7 +53,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel mWater->setCastShadows(false); mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode(); - mWaterNode->setPosition(0, mTop, 0); mReflectionCamera = mSceneManager->createCamera("ReflectionCamera"); @@ -44,27 +65,38 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel applyRTT(); applyVisibilityMask(); - - createMaterial(); mWater->setMaterial(mMaterial); - mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water"); + /* + Ogre::Entity* underwaterDome = mSceneManager->createEntity ("underwater_dome.mesh"); + underwaterDome->setRenderQueueGroup (RQG_UnderWater); + mUnderwaterDome = mSceneManager->getRootSceneNode ()->createChildSceneNode (); + mUnderwaterDome->attachObject (underwaterDome); + mUnderwaterDome->setScale(10000,10000,10000); + mUnderwaterDome->setVisible(false); + underwaterDome->setMaterialName("Underwater_Dome"); + */ mSceneManager->addRenderQueueListener(this); assignTextures(); + setHeight(mTop); + + sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); + m->setListener (this); + // ---------------------------------------------------------------------------------------------- // ---------------------------------- reflection debug overlay ---------------------------------- // ---------------------------------------------------------------------------------------------- - /* +/* if (Settings::Manager::getBool("shader", "Water")) { OverlayManager& mgr = OverlayManager::getSingleton(); Overlay* overlay; // destroy if already exists - if (overlay = mgr.getByName("ReflectionDebugOverlay")) + if ((overlay = mgr.getByName("ReflectionDebugOverlay"))) mgr.destroy(overlay); overlay = mgr.create("ReflectionDebugOverlay"); @@ -76,18 +108,17 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); - TextureUnitState *t = debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(tex->getName()); - t->setTextureAddressingMode(TextureUnitState::TAM_CLAMP); + debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(mReflectionTexture->getName()); OverlayContainer* debugPanel; // destroy container if exists try { - if (debugPanel = + if ((debugPanel = static_cast( mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel" - ))) + )))) mgr.destroyOverlayElement(debugPanel); } catch (Ogre::Exception&) {} @@ -101,13 +132,15 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel overlay->add2D(debugPanel); overlay->show(); } - */ +*/ } void Water::setActive(bool active) { mActive = active; updateVisible(); + + sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0 : 0.0))); } Water::~Water() @@ -135,8 +168,14 @@ void Water::changeCell(const ESM::Cell* cell) void Water::setHeight(const float height) { mTop = height; + mWaterPlane = Plane(Vector3::UNIT_Y, height); + + // small error due to reflection texture size & reflection distortion + mErrorPlane = Plane(Vector3::UNIT_Y, height - 5); + mWaterNode->setPosition(0, height, 0); + sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); } void Water::toggle() @@ -145,42 +184,16 @@ void Water::toggle() updateVisible(); } -void Water::checkUnderwater(float y) +void +Water::updateUnderwater(bool underwater) { - if (!mActive) - { - mRendering->getCompositors()->setCompositorEnabled(mCompositorName, false); + if (!mActive) { return; } - - if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) - { - mRendering->getCompositors()->setCompositorEnabled(mCompositorName, false); - - // tell the shader we are not underwater - Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); - if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false)) - pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(0)); - - mWater->setRenderQueueGroup(RQG_Water); - - mIsUnderwater = false; - } - - if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID) - { - if (mUnderwaterEffect) - mRendering->getCompositors()->setCompositorEnabled(mCompositorName, true); - - // tell the shader we are underwater - Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0); - if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false)) - pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(1)); - - mWater->setRenderQueueGroup(RQG_UnderWater); - - mIsUnderwater = true; - } + mIsUnderwater = + underwater && + mWater->isVisible() && + mCamera->getPolygonMode() == Ogre::PM_SOLID; updateVisible(); } @@ -202,12 +215,11 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) mReflectionCamera->setFOVy(mCamera->getFOVy()); mReflectionRenderActive = true; - /// \todo For some reason this camera is delayed for 1 frame, which causes ugly sky reflection behaviour.. - /// to circumvent this we just scale the sky up, so it's not that noticable + /// \todo the reflection render (and probably all renderingmanager-updates) lag behind 1 camera frame for some reason Vector3 pos = mCamera->getRealPosition(); pos.y = mTop*2 - pos.y; mSky->setSkyPosition(pos); - mSky->scaleSky(mCamera->getFarClipDistance() / 5000.f); + mSky->scaleSky(mCamera->getFarClipDistance() / 50.f); mReflectionCamera->enableReflection(mWaterPlane); } } @@ -224,48 +236,18 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) } } -void Water::createMaterial() -{ - if (mReflectionTarget == 0) - { - mMaterial = MaterialManager::getSingleton().getByName("Water_Fallback"); - } - else - { - mMaterial = MaterialManager::getSingleton().getByName("Water"); - mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTexture(mReflectionTexture); - } - - // these have to be set in code - std::string textureNames[32]; - for (int i=0; i<32; ++i) - { - textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds"; - } - Ogre::Technique* tech; - if (mReflectionTarget == 0) - tech = mMaterial->getTechnique(0); - else - tech = mMaterial->getTechnique(1); - - tech->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); -} - void Water::assignTextures() { if (Settings::Manager::getBool("shader", "Water")) { + CompositorInstance* compositor = CompositorManager::getSingleton().getCompositorChain(mRendering->getViewport())->getCompositor("gbuffer"); TexturePtr colorTexture = compositor->getTextureInstance("mrt_output", 0); - TextureUnitState* tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("refractionMap"); - if (tus != 0) - tus->setTexture(colorTexture); + sh::Factory::getInstance ().setTextureAlias ("WaterRefraction", colorTexture->getName()); TexturePtr depthTexture = compositor->getTextureInstance("mrt_output", 1); - tus = mMaterial->getTechnique(0)->getPass(0)->getTextureUnitState("depthMap"); - if (tus != 0) - tus->setTexture(depthTexture); + sh::Factory::getInstance ().setTextureAlias ("SceneDepth", depthTexture->getName()); } } @@ -279,7 +261,7 @@ void Water::updateVisible() { mWater->setVisible(mToggled && mActive); if (mReflectionTarget) - mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater); + mReflectionTarget->setActive(mToggled && mActive); } void Water::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) @@ -287,22 +269,48 @@ void Water::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &in // We don't want the sky to get clipped by custom near clip plane (the water plane) if (queueGroupId < 20 && mReflectionRenderActive) { + mOldFarClip = mReflectionCamera->getFarClipDistance (); mReflectionCamera->disableCustomNearClipPlane(); + mReflectionCamera->setFarClipDistance (1000000000); Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); } + else if (queueGroupId == RQG_UnderWater) + {/* + mOldFarClip2 = mCamera->getFarClipDistance (); + mCamera->setFarClipDistance (1000000000); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + */} } void Water::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) { if (queueGroupId < 20 && mReflectionRenderActive) { - mReflectionCamera->enableCustomNearClipPlane(mWaterPlane); + mReflectionCamera->setFarClipDistance (mOldFarClip); + if (!mIsUnderwater) + mReflectionCamera->enableCustomNearClipPlane(mErrorPlane); Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); } + if (queueGroupId == RQG_UnderWater) + { + /* + mCamera->setFarClipDistance (mOldFarClip2); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); + */} } -void Water::update() +void Water::update(float dt) { + /* + Ogre::Vector3 pos = mCamera->getDerivedPosition (); + pos.y = -mWaterPlane.d; + mUnderwaterDome->setPosition (pos); + */ + + mWaterTimer += dt / 30.0 * MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); + + mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); } void Water::applyRTT() @@ -327,14 +335,14 @@ void Water::applyRTT() vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); vp->setShadowsEnabled(false); // use fallback techniques without shadows and without mrt (currently not implemented for sky and terrain) - //vp->setMaterialScheme("Fallback"); + vp->setMaterialScheme("water_reflection"); rtt->addListener(this); rtt->setActive(true); mReflectionTarget = rtt; - } - mCompositorName = RenderingManager::useMRT() ? "Underwater" : "UnderwaterNoMRT"; + sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mReflectionTexture->getName()); + } } void Water::applyVisibilityMask() @@ -377,7 +385,6 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin { applyRTT(); applyVisibilityMask(); - createMaterial(); mWater->setMaterial(mMaterial); assignTextures(); } @@ -385,4 +392,29 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin applyVisibilityMask(); } +void Water::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) +{ +} + +void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) +{ + if (configuration == "local_map" || !Settings::Manager::getBool("shader", "Water")) + { + // for simple water, set animated texture names + // these have to be set in code + std::string textureNames[32]; + for (int i=0; i<32; ++i) + { + textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds"; + } + + Ogre::Technique* t = static_cast(m->getMaterial())->getOgreTechniqueForConfiguration(configuration); + if (t->getPass(0)->getNumTextureUnitStates () == 0) + return; + t->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); + t->getPass(0)->setDepthWriteEnabled (false); + t->getPass(0)->setSceneBlending (Ogre::SBT_TRANSPARENT_ALPHA); + } +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 4d617ea47..f56ba7410 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -1,34 +1,60 @@ #ifndef GAME_MWRENDER_WATER_H #define GAME_MWRENDER_WATER_H -#include +#include +#include +#include +#include +#include +#include + #include #include #include "renderconst.hpp" +#include + +namespace Ogre +{ + class Camera; + class SceneManager; + class SceneNode; + class Entity; + class Vector3; + struct RenderTargetEvent; +}; namespace MWRender { class SkyManager; class RenderingManager; - /// Water rendering - class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener + /// Water rendering + class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener, public sh::MaterialInstanceListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; Ogre::SceneManager *mSceneManager; Ogre::Plane mWaterPlane; + Ogre::Plane mErrorPlane; + Ogre::SceneNode *mWaterNode; Ogre::Entity *mWater; + //Ogre::SceneNode* mUnderwaterDome; + bool mIsUnderwater; bool mActive; bool mToggled; int mTop; + int mOldFarClip; + int mOldFarClip2; + + float mWaterTimer; + bool mReflectionRenderActive; Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); @@ -50,7 +76,6 @@ namespace MWRender { std::string mCompositorName; - void createMaterial(); Ogre::MaterialPtr mMaterial; Ogre::Camera* mReflectionCamera; @@ -68,7 +93,7 @@ namespace MWRender { void setActive(bool active); void toggle(); - void update(); + void update(float dt); void assignTextures(); @@ -76,10 +101,14 @@ namespace MWRender { void processChangedSettings(const Settings::CategorySettingVector& settings); - void checkUnderwater(float y); + /// Updates underwater state accordingly + void updateUnderwater(bool underwater); void changeCell(const ESM::Cell* cell); void setHeight(const float height); + virtual void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration); + virtual void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration); + }; } diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 08b1f6f8c..9d70c28bd 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -7,6 +7,8 @@ #include #include +#include "../mwworld/class.hpp" + #include "../mwmechanics/creaturestats.hpp" #include "interpretercontext.hpp" @@ -128,7 +130,7 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mHello = value; + MWWorld::Class::get (ptr).getCreatureStats (ptr).setHello(value); } }; @@ -144,7 +146,7 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mFight = value; + MWWorld::Class::get (ptr).getCreatureStats (ptr).setFight(value); } }; @@ -160,7 +162,7 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mFlee = value; + MWWorld::Class::get (ptr).getCreatureStats (ptr).setFlee(value); } }; @@ -176,7 +178,7 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mAlarm = value; + MWWorld::Class::get (ptr).getCreatureStats (ptr).setAlarm(value); } }; diff --git a/apps/openmw/mwscript/animationextensions.cpp b/apps/openmw/mwscript/animationextensions.cpp index 864a2bf1d..6f9253e5d 100644 --- a/apps/openmw/mwscript/animationextensions.cpp +++ b/apps/openmw/mwscript/animationextensions.cpp @@ -9,7 +9,7 @@ #include #include -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" #include "interpretercontext.hpp" #include "ref.hpp" diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index a5db5fd5f..c1d09fac4 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -1,6 +1,8 @@ #include "cellextensions.hpp" +#include + #include #include @@ -8,8 +10,8 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/player.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 0a6ffd0c7..139a5cc6c 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -1,11 +1,16 @@ #include "compilercontext.hpp" +#include + +#include + #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/scriptmanager.hpp" -#include "../mwworld/world.hpp" - -#include "scriptmanager.hpp" +#include "../mwworld/ptr.hpp" +#include "../mwworld/class.hpp" namespace MWScript { diff --git a/apps/openmw/mwscript/consoleextensions.cpp b/apps/openmw/mwscript/consoleextensions.cpp new file mode 100644 index 000000000..00b4f74e5 --- /dev/null +++ b/apps/openmw/mwscript/consoleextensions.cpp @@ -0,0 +1,24 @@ + +#include "consoleextensions.hpp" + +#include + +#include +#include +#include + +namespace MWScript +{ + namespace Console + { + void registerExtensions (Compiler::Extensions& extensions) + { + + } + + void installOpcodes (Interpreter::Interpreter& interpreter) + { + + } + } +} diff --git a/apps/openmw/mwscript/consoleextensions.hpp b/apps/openmw/mwscript/consoleextensions.hpp new file mode 100644 index 000000000..b10bf06a8 --- /dev/null +++ b/apps/openmw/mwscript/consoleextensions.hpp @@ -0,0 +1,25 @@ +#ifndef GAME_SCRIPT_CONSOLEEXTENSIONS_H +#define GAME_SCRIPT_CONSOLEEXTENSIONS_H + +namespace Compiler +{ + class Extensions; +} + +namespace Interpreter +{ + class Interpreter; +} + +namespace MWScript +{ + /// \brief Script functionality limited to the console + namespace Console + { + void registerExtensions (Compiler::Extensions& extensions); + + void installOpcodes (Interpreter::Interpreter& interpreter); + } +} + +#endif diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 1a7b45246..bd14e7b8d 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -8,16 +8,16 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" #include "../mwmechanics/npcstats.hpp" #include "interpretercontext.hpp" #include "ref.hpp" -#include - namespace MWScript { namespace Control @@ -35,10 +35,9 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - if (mEnable) - std::cout << "enable: " << mControl << std::endl; - else - std::cout << "disable: " << mControl << std::endl; + MWBase::Environment::get() + .getInputManager() + ->toggleControlSwitch(mControl, mEnable); } }; @@ -58,54 +57,36 @@ namespace MWScript }; template - class OpClearForceRun : public Interpreter::Opcode0 + class OpClearMovementFlag : public Interpreter::Opcode0 { + MWMechanics::NpcStats::Flag mFlag; + public: + OpClearMovementFlag (MWMechanics::NpcStats::Flag flag) : mFlag (flag) {} + virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - MWWorld::Class::get (ptr).getNpcStats (ptr).mForceRun = false; + MWWorld::Class::get (ptr).getNpcStats (ptr).setMovementFlag (mFlag, false); } }; template - class OpForceRun : public Interpreter::Opcode0 + class OpSetMovementFlag : public Interpreter::Opcode0 { + MWMechanics::NpcStats::Flag mFlag; + public: + OpSetMovementFlag (MWMechanics::NpcStats::Flag flag) : mFlag (flag) {} + virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); - MWWorld::Class::get (ptr).getNpcStats (ptr).mForceRun = true; - } - }; - - template - class OpClearForceSneak : public Interpreter::Opcode0 - { - public: - - virtual void execute (Interpreter::Runtime& runtime) - { - MWWorld::Ptr ptr = R()(runtime); - - MWWorld::Class::get (ptr).getNpcStats (ptr).mForceSneak = false; - } - }; - - template - class OpForceSneak : public Interpreter::Opcode0 - { - public: - - virtual void execute (Interpreter::Runtime& runtime) - { - MWWorld::Ptr ptr = R()(runtime); - - MWWorld::Class::get (ptr).getNpcStats (ptr).mForceSneak = true; + MWWorld::Class::get (ptr).getNpcStats (ptr).setMovementFlag (mFlag, true); } }; @@ -164,19 +145,23 @@ namespace MWScript interpreter.installSegment5 (opcodeToggleCollision, new OpToggleCollision); - interpreter.installSegment5 (opcodeClearForceRun, new OpClearForceRun); - interpreter.installSegment5 (opcodeForceRun, new OpForceRun); - interpreter.installSegment5 (opcodeClearForceSneak, new OpClearForceSneak); - interpreter.installSegment5 (opcodeForceSneak, new OpForceSneak); + interpreter.installSegment5 (opcodeClearForceRun, + new OpClearMovementFlag (MWMechanics::NpcStats::Flag_ForceRun)); + interpreter.installSegment5 (opcodeForceRun, + new OpSetMovementFlag (MWMechanics::NpcStats::Flag_ForceRun)); + interpreter.installSegment5 (opcodeClearForceSneak, + new OpClearMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); + interpreter.installSegment5 (opcodeForceSneak, + new OpSetMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); interpreter.installSegment5 (opcodeClearForceRunExplicit, - new OpClearForceRun); + new OpClearMovementFlag (MWMechanics::NpcStats::Flag_ForceRun)); interpreter.installSegment5 (opcodeForceRunExplicit, - new OpForceRun); + new OpSetMovementFlag (MWMechanics::NpcStats::Flag_ForceRun)); interpreter.installSegment5 (opcodeClearForceSneakExplicit, - new OpClearForceSneak); + new OpClearMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); interpreter.installSegment5 (opcodeForceSneakExplicit, - new OpForceSneak); + new OpSetMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); } } } diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index ec8ab59b4..21c21acf0 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -7,8 +7,9 @@ #include #include -#include "../mwdialogue/journal.hpp" -#include "../mwdialogue/dialoguemanager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/dialoguemanager.hpp" +#include "../mwbase/journal.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -84,7 +85,7 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWDialogue::DialogueManager* dialogue = MWBase::Environment::get().getDialogueManager(); + MWBase::DialogueManager* dialogue = MWBase::Environment::get().getDialogueManager(); while(arg0>0) { std::string question = runtime.getStringLiteral (runtime[0].mInteger); diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 8a166eff3..1ea5f8e3e 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -165,4 +165,20 @@ op 0x2000160: SetFlee op 0x2000161: SetFlee, explicit reference op 0x2000162: SetAlarm op 0x2000163: SetAlarm, explicit reference -opcodes 0x2000164-0x3ffffff unused +op 0x2000164: SetScale +op 0x2000165: SetScale, explicit reference +op 0x2000166: SetAngle +op 0x2000167: SetAngle, explicit reference +op 0x2000168: GetScale +op 0x2000169: GetScale, explicit reference +op 0x200016a: GetAngle +op 0x200016b: GetAngle, explicit reference +op 0x200016c: user1 (console only, requires --script-console switch) +op 0x200016d: user2 (console only, requires --script-console switch) +op 0x200016e: user3, explicit reference (console only, requires --script-console switch) +op 0x200016f: user3 (implicit reference, console only, requires --script-console switch) +op 0x2000170: user4, explicit reference (console only, requires --script-console switch) +op 0x2000171: user4 (implicit reference, console only, requires --script-console switch) +op 0x2000172: GetStartingAngle +op 0x2000173: GetStartingAngle, explicit reference +opcodes 0x2000174-0x3ffffff unused diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 197494146..1b1560820 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -15,10 +15,13 @@ #include "controlextensions.hpp" #include "dialogueextensions.hpp" #include "animationextensions.hpp" +#include "transformationextensions.hpp" +#include "consoleextensions.hpp" +#include "userextensions.hpp" namespace MWScript { - void registerExtensions (Compiler::Extensions& extensions) + void registerExtensions (Compiler::Extensions& extensions, bool consoleOnly) { Cell::registerExtensions (extensions); Misc::registerExtensions (extensions); @@ -31,9 +34,16 @@ namespace MWScript Control::registerExtensions (extensions); Dialogue::registerExtensions (extensions); Animation::registerExtensions (extensions); + Transformation::registerExtensions (extensions); + + if (consoleOnly) + { + Console::registerExtensions (extensions); + User::registerExtensions (extensions); + } } - void installOpcodes (Interpreter::Interpreter& interpreter) + void installOpcodes (Interpreter::Interpreter& interpreter, bool consoleOnly) { Interpreter::installOpcodes (interpreter); Cell::installOpcodes (interpreter); @@ -47,5 +57,12 @@ namespace MWScript Control::installOpcodes (interpreter); Dialogue::installOpcodes (interpreter); Animation::installOpcodes (interpreter); + Transformation::installOpcodes (interpreter); + + if (consoleOnly) + { + Console::installOpcodes (interpreter); + User::installOpcodes (interpreter); + } } } diff --git a/apps/openmw/mwscript/extensions.hpp b/apps/openmw/mwscript/extensions.hpp index 9738367a0..cb1aaf9db 100644 --- a/apps/openmw/mwscript/extensions.hpp +++ b/apps/openmw/mwscript/extensions.hpp @@ -13,9 +13,11 @@ namespace Interpreter namespace MWScript { - void registerExtensions (Compiler::Extensions& extensions); - - void installOpcodes (Interpreter::Interpreter& interpreter); + void registerExtensions (Compiler::Extensions& extensions, bool consoleOnly = false); + ///< \param consoleOnly include console only extensions + + void installOpcodes (Interpreter::Interpreter& interpreter, bool consoleOnly = false); + ///< \param consoleOnly include console only opcodes } #endif diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index eb96ba5e2..6407bf0cb 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -3,13 +3,18 @@ #include +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/scriptmanager.hpp" + #include "interpretercontext.hpp" -#include "scriptmanager.hpp" namespace MWScript { - GlobalScripts::GlobalScripts (const ESMS::ESMStore& store, ScriptManager& scriptManager) - : mStore (store), mScriptManager (scriptManager) + GlobalScripts::GlobalScripts (const ESMS::ESMStore& store) + : mStore (store) { addScript ("Main"); @@ -60,9 +65,8 @@ namespace MWScript { MWScript::InterpreterContext interpreterContext ( &iter->second.second, MWWorld::Ptr()); - mScriptManager.run (iter->first, interpreterContext); + MWBase::Environment::get().getScriptManager()->run (iter->first, interpreterContext); } } - } } diff --git a/apps/openmw/mwscript/globalscripts.hpp b/apps/openmw/mwscript/globalscripts.hpp index 3d62e4d7a..cc2f7ffdd 100644 --- a/apps/openmw/mwscript/globalscripts.hpp +++ b/apps/openmw/mwscript/globalscripts.hpp @@ -13,17 +13,14 @@ namespace ESMS namespace MWScript { - class ScriptManager; - class GlobalScripts { const ESMS::ESMStore& mStore; - ScriptManager& mScriptManager; std::map > mScripts; // running, local variables public: - GlobalScripts (const ESMS::ESMStore& store, ScriptManager& scriptManager); + GlobalScripts (const ESMS::ESMStore& store); void addScript (const std::string& name); diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 8e5897298..d740e5feb 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -8,9 +8,7 @@ #include #include "../mwbase/environment.hpp" - -#include "../mwgui/window_manager.hpp" -#include "../mwinput/inputmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 152fcf85c..075ac5646 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -3,21 +3,20 @@ #include #include -#include #include +#include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/scriptmanager.hpp" +#include "../mwbase/windowmanager.hpp" -#include "../mwworld/world.hpp" - -#include "../mwgui/window_manager.hpp" - -#include "../mwinput/inputmanager.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" #include "locals.hpp" #include "globalscripts.hpp" -#include "scriptmanager.hpp" namespace MWScript { @@ -236,7 +235,7 @@ namespace MWScript if (!mAction.get()) throw std::runtime_error ("activation failed, because no action to perform"); - mAction->execute(); + mAction->execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mActivationHandled = true; } diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 9fdc3c21a..6d97f7949 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -5,8 +5,9 @@ #include +#include "../mwbase/world.hpp" + #include "../mwworld/ptr.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/action.hpp" namespace MWSound diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index c7569ccdd..0c328e0da 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -1,6 +1,8 @@ #include "miscextensions.hpp" +#include + #include #include @@ -102,7 +104,7 @@ namespace MWScript static_cast (runtime.getContext()); bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWWorld::World::Render_CollisionDebug); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_CollisionDebug); context.report (enabled ? "Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off"); @@ -119,7 +121,7 @@ namespace MWScript static_cast (runtime.getContext()); bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWWorld::World::Render_Wireframe); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Wireframe); context.report (enabled ? "Wireframe Rendering -> On" : "Wireframe Rendering -> Off"); @@ -135,7 +137,7 @@ namespace MWScript static_cast (runtime.getContext()); bool enabled = - MWBase::Environment::get().getWorld()->toggleRenderMode (MWWorld::World::Render_Pathgrid); + MWBase::Environment::get().getWorld()->toggleRenderMode (MWBase::World::Render_Pathgrid); context.report (enabled ? "Path Grid rendering -> On" : "Path Grid Rendering -> Off"); diff --git a/apps/openmw/mwscript/ref.hpp b/apps/openmw/mwscript/ref.hpp index 28093c4e5..81b1d5ef9 100644 --- a/apps/openmw/mwscript/ref.hpp +++ b/apps/openmw/mwscript/ref.hpp @@ -6,9 +6,9 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/ptr.hpp" -#include "../mwworld/world.hpp" #include "interpretercontext.hpp" diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp similarity index 98% rename from apps/openmw/mwscript/scriptmanager.cpp rename to apps/openmw/mwscript/scriptmanagerimp.cpp index d8bd269c6..0b33d43fa 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -1,5 +1,5 @@ -#include "scriptmanager.hpp" +#include "scriptmanagerimp.hpp" #include #include @@ -21,7 +21,7 @@ namespace MWScript Compiler::Context& compilerContext) : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), - mOpcodesInstalled (false), mGlobalScripts (store, *this) + mOpcodesInstalled (false), mGlobalScripts (store) {} bool ScriptManager::compile (const std::string& name) diff --git a/apps/openmw/mwscript/scriptmanager.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp similarity index 75% rename from apps/openmw/mwscript/scriptmanager.hpp rename to apps/openmw/mwscript/scriptmanagerimp.hpp index 34cc0defe..bacc232b2 100644 --- a/apps/openmw/mwscript/scriptmanager.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -2,7 +2,6 @@ #define GAME_SCRIPT_SCRIPTMANAGER_H #include -#include #include #include @@ -11,6 +10,8 @@ #include #include +#include "../mwbase/scriptmanager.hpp" + #include "globalscripts.hpp" namespace ESMS @@ -31,7 +32,7 @@ namespace Interpreter namespace MWScript { - class ScriptManager + class ScriptManager : public MWBase::ScriptManager { Compiler::StreamErrorHandler mErrorHandler; const ESMS::ESMStore& mStore; @@ -52,23 +53,24 @@ namespace MWScript ScriptManager (const ESMS::ESMStore& store, bool verbose, Compiler::Context& compilerContext); - void run (const std::string& name, Interpreter::Context& interpreterContext); + virtual void run (const std::string& name, Interpreter::Context& interpreterContext); ///< Run the script with the given name (compile first, if not compiled yet) - bool compile (const std::string& name); + virtual bool compile (const std::string& name); ///< Compile script with the given namen /// \return Success? - std::pair compileAll(); + virtual std::pair compileAll(); ///< Compile all scripts /// \return count, success - Compiler::Locals& getLocals (const std::string& name); + virtual Compiler::Locals& getLocals (const std::string& name); ///< Return locals for script \a name. - GlobalScripts& getGlobalScripts(); + virtual GlobalScripts& getGlobalScripts(); - int getLocalIndex (const std::string& scriptId, const std::string& variable, char type); + virtual int getLocalIndex (const std::string& scriptId, const std::string& variable, + char type); ///< Return index of the variable of the given name and type in the given script. Will /// throw an exception, if there is no such script or variable or the type does not match. }; diff --git a/apps/openmw/mwscript/soundextensions.cpp b/apps/openmw/mwscript/soundextensions.cpp index c2b45641a..6dc8f3919 100644 --- a/apps/openmw/mwscript/soundextensions.cpp +++ b/apps/openmw/mwscript/soundextensions.cpp @@ -8,10 +8,8 @@ #include #include "../mwbase/environment.hpp" - -#include "../mwworld/world.hpp" - -#include "../mwsound/soundmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -117,7 +115,7 @@ namespace MWScript std::string sound = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWSound::Play_Loop : 0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, 1.0, 1.0, mLoop ? MWBase::SoundManager::Play_Loop : 0); } }; @@ -143,7 +141,7 @@ namespace MWScript Interpreter::Type_Float pitch = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWSound::Play_Loop : 0); + MWBase::Environment::get().getSoundManager()->playSound3D (ptr, sound, volume, pitch, mLoop ? MWBase::SoundManager::Play_Loop : 0); } }; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index d23519281..5113c9dbf 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1,8 +1,14 @@ #include "statsextensions.hpp" +#include + #include +#include + +#include + #include #include @@ -10,6 +16,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -20,7 +27,6 @@ #include "interpretercontext.hpp" #include "ref.hpp" -#include "../mwdialogue/dialoguemanager.hpp" namespace MWScript { @@ -40,8 +46,10 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer value = - MWWorld::Class::get (ptr).getCreatureStats (ptr).mAttributes[mIndex]. - getModified(); + MWWorld::Class::get (ptr) + .getCreatureStats (ptr) + .getAttribute(mIndex) + .getModified(); runtime.push (value); } @@ -63,8 +71,10 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mAttributes[mIndex]. - setModified (value, 0); + MWWorld::Class::get(ptr) + .getCreatureStats(ptr) + .getAttribute(mIndex) + .setModified (value, 0); } }; @@ -84,11 +94,16 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - value += MWWorld::Class::get (ptr).getCreatureStats (ptr).mAttributes[mIndex]. - getModified(); + value += + MWWorld::Class::get(ptr) + .getCreatureStats(ptr) + .getAttribute(mIndex) + .getModified(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mAttributes[mIndex]. - setModified (value, 0, 100); + MWWorld::Class::get(ptr) + .getCreatureStats(ptr) + .getAttribute(mIndex) + .setModified (value, 0, 100); } }; @@ -104,21 +119,19 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); + Interpreter::Type_Integer value; if (mIndex==0 && MWWorld::Class::get (ptr).hasItemHealth (ptr)) { // health is a special case - Interpreter::Type_Integer value = - MWWorld::Class::get (ptr).getItemMaxHealth (ptr); - runtime.push (value); - - return; + value = MWWorld::Class::get (ptr).getItemMaxHealth (ptr); + } else { + value = + MWWorld::Class::get(ptr) + .getCreatureStats(ptr) + .getDynamic(mIndex) + .getCurrent(); } - - Interpreter::Type_Integer value = - MWWorld::Class::get (ptr).getCreatureStats (ptr).mDynamic[mIndex]. - getCurrent(); - runtime.push (value); } }; @@ -139,8 +152,10 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mDynamic[mIndex]. - setModified (value, 0); + MWWorld::Class::get(ptr) + .getCreatureStats(ptr) + .getDynamic(mIndex) + .setModified(value, 0); } }; @@ -162,12 +177,12 @@ namespace MWScript MWMechanics::CreatureStats& stats = MWWorld::Class::get (ptr).getCreatureStats (ptr); - Interpreter::Type_Integer current = stats.mDynamic[mIndex].getCurrent(); + Interpreter::Type_Integer current = stats.getDynamic(mIndex).getCurrent(); - stats.mDynamic[mIndex].setModified ( - diff + stats.mDynamic[mIndex].getModified(), 0); + stats.getDynamic(mIndex).setModified( + diff + stats.getDynamic(mIndex).getModified(), 0); - stats.mDynamic[mIndex].setCurrent (diff + current); + stats.getDynamic(mIndex).setCurrent(diff + current); } }; @@ -189,9 +204,9 @@ namespace MWScript MWMechanics::CreatureStats& stats = MWWorld::Class::get (ptr).getCreatureStats (ptr); - Interpreter::Type_Integer current = stats.mDynamic[mIndex].getCurrent(); + Interpreter::Type_Integer current = stats.getDynamic(mIndex).getCurrent(); - stats.mDynamic[mIndex].setCurrent (diff + current); + stats.getDynamic(mIndex).setCurrent (diff + current); } }; @@ -212,10 +227,10 @@ namespace MWScript Interpreter::Type_Float value = 0; - Interpreter::Type_Float max = stats.mDynamic[mIndex].getModified(); + Interpreter::Type_Float max = stats.getDynamic(mIndex).getModified(); if (max>0) - value = stats.mDynamic[mIndex].getCurrent() / max; + value = stats.getDynamic(mIndex).getCurrent() / max; runtime.push (value); } @@ -235,7 +250,7 @@ namespace MWScript MWWorld::Ptr ptr = R()(runtime); Interpreter::Type_Integer value = - MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex]. + MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex). getModified(); runtime.push (value); @@ -258,8 +273,35 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex]. - setModified (value, 0); + MWMechanics::NpcStats& stats = MWWorld::Class::get (ptr).getNpcStats (ptr); + + MWWorld::LiveCellRef *ref = ptr.get(); + + assert (ref); + + const ESM::Class& class_ = + *MWBase::Environment::get().getWorld()->getStore().classes.find (ref->base->cls); + + float level = 0; + float progress = std::modf (stats.getSkill (mIndex).getBase(), &level); + + float modifier = stats.getSkill (mIndex).getModifier(); + + int newLevel = static_cast (value-modifier); + + if (newLevel<0) + newLevel = 0; + else if (newLevel>100) + newLevel = 100; + + progress = (progress / stats.getSkillGain (mIndex, class_, -1, level)) + * stats.getSkillGain (mIndex, class_, -1, newLevel); + + if (progress>=1) + progress = 0.999999999; + + stats.getSkill (mIndex).set (newLevel + progress); + stats.getSkill (mIndex).setModifier (modifier); } }; @@ -279,10 +321,10 @@ namespace MWScript Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - value += MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex]. + value += MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex). getModified(); - MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex]. + MWWorld::Class::get (ptr).getNpcStats (ptr).getSkill (mIndex). setModified (value, 0, 100); } }; @@ -299,7 +341,10 @@ namespace MWScript std::string id = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mSpells.add (id); + // make sure a spell with this ID actually exists. + MWBase::Environment::get().getWorld()->getStore().spells.find (id); + + MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().add (id); } }; @@ -315,7 +360,7 @@ namespace MWScript std::string id = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWWorld::Class::get (ptr).getCreatureStats (ptr).mSpells.remove (id); + MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().remove (id); } }; @@ -335,8 +380,8 @@ namespace MWScript Interpreter::Type_Integer value = 0; for (MWMechanics::Spells::TIterator iter ( - MWWorld::Class::get (ptr).getCreatureStats (ptr).mSpells.begin()); - iter!=MWWorld::Class::get (ptr).getCreatureStats (ptr).mSpells.end(); ++iter) + MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().begin()); + iter!=MWWorld::Class::get (ptr).getCreatureStats (ptr).getSpells().end(); ++iter) if (*iter==id) { value = 1; @@ -368,9 +413,9 @@ namespace MWScript if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) + if(MWWorld::Class::get(player).getNpcStats(player).getFactionRanks().find(factionID) == MWWorld::Class::get(player).getNpcStats(player).getFactionRanks().end()) { - MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 0; + MWWorld::Class::get(player).getNpcStats(player).getFactionRanks()[factionID] = 0; } } } @@ -397,13 +442,13 @@ namespace MWScript if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) == MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) + if(MWWorld::Class::get(player).getNpcStats(player).getFactionRanks().find(factionID) == MWWorld::Class::get(player).getNpcStats(player).getFactionRanks().end()) { - MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = 0; + MWWorld::Class::get(player).getNpcStats(player).getFactionRanks()[factionID] = 0; } else { - MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] +1; + MWWorld::Class::get(player).getNpcStats(player).getFactionRanks()[factionID] = MWWorld::Class::get(player).getNpcStats(player).getFactionRanks()[factionID] +1; } } } @@ -430,9 +475,9 @@ namespace MWScript if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) != MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) + if(MWWorld::Class::get(player).getNpcStats(player).getFactionRanks().find(factionID) != MWWorld::Class::get(player).getNpcStats(player).getFactionRanks().end()) { - MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] = MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID] -1; + MWWorld::Class::get(player).getNpcStats(player).getFactionRanks()[factionID] = MWWorld::Class::get(player).getNpcStats(player).getFactionRanks()[factionID] -1; } } } @@ -455,22 +500,22 @@ namespace MWScript } else { - if(MWWorld::Class::get(ptr).getNpcStats(ptr).mFactionRank.empty()) + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) { //throw exception? } else { - factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).mFactionRank.begin()->first; + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; } } boost::algorithm::to_lower(factionID); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(factionID!="") { - if(MWWorld::Class::get(player).getNpcStats(player).mFactionRank.find(factionID) != MWWorld::Class::get(player).getNpcStats(player).mFactionRank.end()) + if(MWWorld::Class::get(player).getNpcStats(player).getFactionRanks().find(factionID) != MWWorld::Class::get(player).getNpcStats(player).getFactionRanks().end()) { - runtime.push(MWWorld::Class::get(player).getNpcStats(player).mFactionRank[factionID]); + runtime.push(MWWorld::Class::get(player).getNpcStats(player).getFactionRanks()[factionID]); } else { @@ -500,6 +545,7 @@ namespace MWScript } }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp new file mode 100644 index 000000000..6f906343c --- /dev/null +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -0,0 +1,178 @@ +#include + +#include + +#include + +#include +#include +#include + +#include "../mwbase/environment.hpp" + +#include "../mwworld/class.hpp" + +#include "interpretercontext.hpp" +#include "ref.hpp" +#include "OgreSceneNode.h" + +namespace MWScript +{ + namespace Transformation + { + template + class OpSetScale : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Float scale = runtime[0].mFloat; + runtime.pop(); + + MWBase::Environment::get().getWorld()->scaleObject(ptr,scale); + } + }; + + template + class OpGetScale : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + runtime.push(ptr.getCellRef().scale); + } + }; + + template + class OpSetAngle : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float angle = runtime[0].mFloat; + runtime.pop(); + + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + + if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az); + } + else if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle); + } + else + throw std::runtime_error ("invalid ration axis: " + axis); + } + }; + + template + class OpGetStartingAngle : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + if (axis == "x") + { + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + } + else if (axis == "y") + { + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + } + else if (axis == "z") + { + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + } + else + throw std::runtime_error ("invalid ration axis: " + axis); + } + }; + + template + class OpGetAngle : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + if (axis=="x") + { + runtime.push(Ogre::Radian(ptr.getCellRef().pos.rot[0]).valueDegrees()); + } + else if (axis=="y") + { + runtime.push(Ogre::Radian(ptr.getCellRef().pos.rot[1]).valueDegrees()); + } + else if (axis=="z") + { + runtime.push(Ogre::Radian(ptr.getCellRef().pos.rot[2]).valueDegrees()); + } + else + throw std::runtime_error ("invalid ration axis: " + axis); + } + }; + + const int opcodeSetScale = 0x2000164; + const int opcodeSetScaleExplicit = 0x2000165; + const int opcodeSetAngle = 0x2000166; + const int opcodeSetAngleExplicit = 0x2000167; + const int opcodeGetScale = 0x2000168; + const int opcodeGetScaleExplicit = 0x2000169; + const int opcodeGetAngle = 0x200016a; + const int opcodeGetAngleExplicit = 0x200016b; + const int opcodeGetStartingAngle = 0x2000172; + const int opcodeGetStartingAngleExplicit = 0x2000173; + + void registerExtensions (Compiler::Extensions& extensions) + { + extensions.registerInstruction("setscale","f",opcodeSetScale,opcodeSetScaleExplicit); + extensions.registerFunction("getscale",'f',"",opcodeGetScale,opcodeGetScaleExplicit); + extensions.registerInstruction("setangle","cf",opcodeSetAngle,opcodeSetAngleExplicit); + extensions.registerFunction("getangle",'f',"c",opcodeGetAngle,opcodeGetAngleExplicit); + extensions.registerFunction("getstartingangle",'f',"c",opcodeGetStartingAngle,opcodeGetStartingAngleExplicit); + } + + void installOpcodes (Interpreter::Interpreter& interpreter) + { + interpreter.installSegment5(opcodeSetScale,new OpSetScale); + interpreter.installSegment5(opcodeSetScaleExplicit,new OpSetScale); + interpreter.installSegment5(opcodeSetAngle,new OpSetAngle); + interpreter.installSegment5(opcodeSetAngleExplicit,new OpSetAngle); + interpreter.installSegment5(opcodeGetScale,new OpGetScale); + interpreter.installSegment5(opcodeGetScaleExplicit,new OpGetScale); + interpreter.installSegment5(opcodeGetAngle,new OpGetAngle); + interpreter.installSegment5(opcodeGetAngleExplicit,new OpGetAngle); + interpreter.installSegment5(opcodeGetStartingAngle,new OpGetStartingAngle); + interpreter.installSegment5(opcodeGetStartingAngleExplicit,new OpGetStartingAngle); + } + } +} diff --git a/apps/openmw/mwscript/transformationextensions.hpp b/apps/openmw/mwscript/transformationextensions.hpp new file mode 100644 index 000000000..6ee1db1b8 --- /dev/null +++ b/apps/openmw/mwscript/transformationextensions.hpp @@ -0,0 +1,25 @@ +#ifndef GAME_SCRIPT_TRANSFORMATIONEXTENSIONS_H +#define GAME_SCRIPT_TRANSFORMATIONEXTENSIONS_H + +namespace Compiler +{ + class Extensions; +} + +namespace Interpreter +{ + class Interpreter; +} + +namespace MWScript +{ + /// \brief stats-related script functionality (creatures and NPCs) + namespace Transformation + { + void registerExtensions (Compiler::Extensions& extensions); + + void installOpcodes (Interpreter::Interpreter& interpreter); + } +} + +#endif \ No newline at end of file diff --git a/apps/openmw/mwscript/userextensions.cpp b/apps/openmw/mwscript/userextensions.cpp new file mode 100644 index 000000000..9c9738815 --- /dev/null +++ b/apps/openmw/mwscript/userextensions.cpp @@ -0,0 +1,91 @@ + +#include "userextensions.hpp" + +#include + +#include +#include +#include +#include + +#include "ref.hpp" + +namespace MWScript +{ + /// Temporary script extensions. + /// + /// \attention Do not commit changes to this file to a git repository! + namespace User + { + class OpUser1 : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + runtime.getContext().report ("user1: not in use"); + } + }; + + class OpUser2 : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + runtime.getContext().report ("user2: not in use"); + } + }; + + template + class OpUser3 : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { +// MWWorld::Ptr ptr = R()(runtime); + + runtime.getContext().report ("user3: not in use"); + } + }; + + template + class OpUser4 : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { +// MWWorld::Ptr ptr = R()(runtime); + + runtime.getContext().report ("user4: not in use"); + } + }; + + const int opcodeUser1 = 0x200016c; + const int opcodeUser2 = 0x200016d; + const int opcodeUser3 = 0x200016e; + const int opcodeUser3Explicit = 0x200016f; + const int opcodeUser4 = 0x2000170; + const int opcodeUser4Explicit = 0x2000171; + + void registerExtensions (Compiler::Extensions& extensions) + { + extensions.registerInstruction ("user1", "", opcodeUser1); + extensions.registerInstruction ("user2", "", opcodeUser2); + extensions.registerInstruction ("user3", "", opcodeUser3, opcodeUser3); + extensions.registerInstruction ("user4", "", opcodeUser4, opcodeUser4); + } + + void installOpcodes (Interpreter::Interpreter& interpreter) + { + interpreter.installSegment5 (opcodeUser1, new OpUser1); + interpreter.installSegment5 (opcodeUser2, new OpUser2); + interpreter.installSegment5 (opcodeUser3, new OpUser3); + interpreter.installSegment5 (opcodeUser3Explicit, new OpUser3); + interpreter.installSegment5 (opcodeUser4, new OpUser4); + interpreter.installSegment5 (opcodeUser4Explicit, new OpUser4); + } + } +} diff --git a/apps/openmw/mwscript/userextensions.hpp b/apps/openmw/mwscript/userextensions.hpp new file mode 100644 index 000000000..3642eb5f4 --- /dev/null +++ b/apps/openmw/mwscript/userextensions.hpp @@ -0,0 +1,25 @@ +#ifndef GAME_SCRIPT_USEREXTENSIONS_H +#define GAME_SCRIPT_USEREXTENSIONS_H + +namespace Compiler +{ + class Extensions; +} + +namespace Interpreter +{ + class Interpreter; +} + +namespace MWScript +{ + /// \brief Temporaty script functionality limited to the console + namespace User + { + void registerExtensions (Compiler::Extensions& extensions); + + void installOpcodes (Interpreter::Interpreter& interpreter); + } +} + +#endif diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp index ac4baa8b2..e5169d878 100644 --- a/apps/openmw/mwsound/openal_output.cpp +++ b/apps/openmw/mwsound/openal_output.cpp @@ -8,7 +8,7 @@ #include "openal_output.hpp" #include "sound_decoder.hpp" #include "sound.hpp" -#include "soundmanager.hpp" +#include "soundmanagerimp.hpp" #ifndef ALC_ALL_DEVICES_SPECIFIER #define ALC_ALL_DEVICES_SPECIFIER 0x1013 @@ -263,7 +263,7 @@ void OpenAL_SoundStream::update() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; - if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -400,7 +400,7 @@ void OpenAL_Sound::update() { ALfloat gain = mVolume*mBaseVolume; ALfloat pitch = mPitch; - if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -420,7 +420,7 @@ void OpenAL_Sound3D::update() ALfloat pitch = mPitch; if(mPos.squaredDistance(mOutput.mPos) > mMaxDistance*mMaxDistance) gain = 0.0f; - else if(!(mFlags&Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) + else if(!(mFlags&MWBase::SoundManager::Play_NoEnv) && mOutput.mLastEnvironment == Env_Underwater) { gain *= 0.9f; pitch *= 0.7f; @@ -642,7 +642,7 @@ void OpenAL_Output::bufferFinished(ALuint buf) } -SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, int flags) +MWBase::SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, int flags) { boost::shared_ptr sound; ALuint src=0, buf=0; @@ -674,7 +674,7 @@ SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float alSourcef(src, AL_MAX_DISTANCE, 1000.0f); alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); - if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) { volume *= 0.9f; pitch *= 0.7f; @@ -683,7 +683,7 @@ SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float alSourcef(src, AL_PITCH, pitch); alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(src, AL_LOOPING, (flags&Play_Loop) ? AL_TRUE : AL_FALSE); + alSourcei(src, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); throwALerror(); alSourcei(src, AL_BUFFER, buf); @@ -693,7 +693,7 @@ SoundPtr OpenAL_Output::playSound(const std::string &fname, float volume, float return sound; } -SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch, +MWBase::SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch, float min, float max, int flags) { boost::shared_ptr sound; @@ -726,7 +726,7 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector alSourcef(src, AL_MAX_DISTANCE, max); alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f); - if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) { volume *= 0.9f; pitch *= 0.7f; @@ -736,7 +736,7 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector alSourcef(src, AL_PITCH, pitch); alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(src, AL_LOOPING, (flags&Play_Loop) ? AL_TRUE : AL_FALSE); + alSourcei(src, AL_LOOPING, (flags&MWBase::SoundManager::Play_Loop) ? AL_TRUE : AL_FALSE); throwALerror(); alSourcei(src, AL_BUFFER, buf); @@ -747,7 +747,7 @@ SoundPtr OpenAL_Output::playSound3D(const std::string &fname, const Ogre::Vector } -SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch, int flags) +MWBase::SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch, int flags) { boost::shared_ptr sound; ALuint src; @@ -759,7 +759,7 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa try { - if((flags&Play_Loop)) + if((flags&MWBase::SoundManager::Play_Loop)) std::cout <<"Warning: cannot loop stream "<open(fname); @@ -779,7 +779,7 @@ SoundPtr OpenAL_Output::streamSound(const std::string &fname, float volume, floa alSourcef(src, AL_MAX_DISTANCE, 1000.0f); alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); - if(!(flags&Play_NoEnv) && mLastEnvironment == Env_Underwater) + if(!(flags&MWBase::SoundManager::Play_NoEnv) && mLastEnvironment == Env_Underwater) { volume *= 0.9f; pitch *= 0.7f; diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp index d62d20286..90917c53c 100644 --- a/apps/openmw/mwsound/openal_output.hpp +++ b/apps/openmw/mwsound/openal_output.hpp @@ -42,10 +42,10 @@ namespace MWSound virtual void init(const std::string &devname=""); virtual void deinit(); - virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags); - virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, + virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags); + virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch, float min, float max, int flags); - virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags); + virtual MWBase::SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags); virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env); diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp index a33892548..729147f75 100644 --- a/apps/openmw/mwsound/sound.hpp +++ b/apps/openmw/mwsound/sound.hpp @@ -3,6 +3,8 @@ #include +#include "soundmanagerimp.hpp" + namespace MWSound { class Sound @@ -33,7 +35,7 @@ namespace MWSound , mPitch(1.0f) , mMinDistance(20.0f) /* 1 * min_range_scale */ , mMaxDistance(12750.0f) /* 255 * max_range_scale */ - , mFlags(Play_Normal) + , mFlags(MWBase::SoundManager::Play_Normal) { } virtual ~Sound() { } diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp index 100b2208c..2680ec1db 100644 --- a/apps/openmw/mwsound/sound_output.hpp +++ b/apps/openmw/mwsound/sound_output.hpp @@ -6,7 +6,7 @@ #include -#include "soundmanager.hpp" +#include "soundmanagerimp.hpp" #include "../mwworld/ptr.hpp" @@ -24,10 +24,10 @@ namespace MWSound virtual void init(const std::string &devname="") = 0; virtual void deinit() = 0; - virtual SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0; - virtual SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, + virtual MWBase::SoundPtr playSound(const std::string &fname, float volume, float pitch, int flags) = 0; + virtual MWBase::SoundPtr playSound3D(const std::string &fname, const Ogre::Vector3 &pos, float volume, float pitch, float min, float max, int flags) = 0; - virtual SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags) = 0; + virtual MWBase::SoundPtr streamSound(const std::string &fname, float volume, float pitch, int flags) = 0; virtual void updateListener(const Ogre::Vector3 &pos, const Ogre::Vector3 &atdir, const Ogre::Vector3 &updir, Environment env) = 0; diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp similarity index 92% rename from apps/openmw/mwsound/soundmanager.cpp rename to apps/openmw/mwsound/soundmanagerimp.cpp index ff618ac33..e1720453b 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -1,16 +1,14 @@ -#include "soundmanager.hpp" +#include "soundmanagerimp.hpp" #include #include #include -#include - #include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" -#include "../mwworld/world.hpp" #include "../mwworld/player.hpp" #include "sound_output.hpp" @@ -88,7 +86,7 @@ namespace MWSound { if(devname.empty()) throw; - std::cout <<"Failed to open device \""<init(); Settings::Manager::setString("device", "Sound", ""); } @@ -220,7 +218,7 @@ namespace MWSound const ESM::Position &pos = ptr.getCellRef().pos; const Ogre::Vector3 objpos(pos.pos[0], pos.pos[1], pos.pos[2]); - SoundPtr sound = mOutput->playSound3D(filePath, objpos, basevol, 1.0f, + MWBase::SoundPtr sound = mOutput->playSound3D(filePath, objpos, basevol, 1.0f, 20.0f, 12750.0f, Play_Normal); sound->mPos = objpos; sound->mBaseVolume = basevol; @@ -242,7 +240,7 @@ namespace MWSound float basevol = mMasterVolume * mVoiceVolume; std::string filePath = "Sound/"+filename; - SoundPtr sound = mOutput->playSound(filePath, basevol, 1.0f, Play_Normal); + MWBase::SoundPtr sound = mOutput->playSound(filePath, basevol, 1.0f, Play_Normal); sound->mBaseVolume = basevol; mActiveSounds[sound] = std::make_pair(MWWorld::Ptr(), std::string("_say_sound")); @@ -275,9 +273,9 @@ namespace MWSound - SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode) + MWBase::SoundPtr SoundManager::playSound(const std::string& soundId, float volume, float pitch, int mode) { - SoundPtr sound; + MWBase::SoundPtr sound; if(!mOutput->isInitialized()) return sound; try @@ -303,10 +301,10 @@ namespace MWSound return sound; } - SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, + MWBase::SoundPtr SoundManager::playSound3D(MWWorld::Ptr ptr, const std::string& soundId, float volume, float pitch, int mode) { - SoundPtr sound; + MWBase::SoundPtr sound; if(!mOutput->isInitialized()) return sound; try @@ -489,25 +487,20 @@ namespace MWSound if(!isMusicPlaying()) startRandomTitle(); - const ESM::Cell *cell = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->cell; - Ogre::Camera *cam = MWBase::Environment::get().getWorld()->getPlayer().getRenderer()->getCamera(); - Ogre::Vector3 nPos, nDir, nUp; - nPos = cam->getRealPosition(); - nDir = cam->getRealDirection(); - nUp = cam->getRealUp(); + MWWorld::Ptr player = + MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + const ESM::Cell *cell = player.getCell()->cell; Environment env = Env_Normal; - if((cell->data.flags&cell->HasWater) && nPos.y < cell->water) + if((cell->data.flags&cell->HasWater) && mListenerPos.z < cell->water) env = Env_Underwater; - // The output handler is expecting vectors oriented like the game - // (that is, -Z goes down, +Y goes forward), but that's not what we - // get from Ogre's camera, so we have to convert. - const Ogre::Vector3 pos(nPos[0], -nPos[2], nPos[1]); - const Ogre::Vector3 at(nDir[0], -nDir[2], nDir[1]); - const Ogre::Vector3 up(nUp[0], -nUp[2], nUp[1]); - - mOutput->updateListener(pos, at, up, env); + mOutput->updateListener( + mListenerPos, + mListenerDir, + Ogre::Vector3::UNIT_Z, + env + ); // Check if any sounds are finished playing, and trash them SoundMap::iterator snditer = mActiveSounds.begin(); @@ -565,6 +558,12 @@ namespace MWSound } } + void SoundManager::setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir) + { + mListenerPos = pos; + mListenerDir = dir; + } + // Default readAll implementation, for decoders that can't do anything // better void Sound_Decoder::readAll(std::vector &output) diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanagerimp.hpp similarity index 56% rename from apps/openmw/mwsound/soundmanager.hpp rename to apps/openmw/mwsound/soundmanagerimp.hpp index 562b2af00..956ad5712 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanagerimp.hpp @@ -5,19 +5,17 @@ #include #include +#include + +#include #include #include +#include "../mwbase/soundmanager.hpp" + #include "../mwworld/ptr.hpp" - -namespace Ogre -{ - class Root; - class Camera; -} - namespace MWSound { class Sound_Output; @@ -25,27 +23,13 @@ namespace MWSound class Sound; typedef boost::shared_ptr DecoderPtr; - typedef boost::shared_ptr SoundPtr; - - enum PlayMode { - Play_Normal = 0, /* tracked, non-looping, multi-instance, environment */ - Play_Loop = 1<<0, /* Sound will continually loop until explicitly stopped */ - Play_NoEnv = 1<<1, /* Do not apply environment effects (eg, underwater filters) */ - Play_NoTrack = 1<<2, /* (3D only) Play the sound at the given object's position - * but do not keep it updated (the sound will not move with - * the object and will not stop when the object is deleted. */ - }; - static inline int operator|(const PlayMode &a, const PlayMode &b) - { return (int)a | (int)b; } - static inline int operator&(const PlayMode &a, const PlayMode &b) - { return (int)a & (int)b; } enum Environment { Env_Normal, Env_Underwater, }; - class SoundManager + class SoundManager : public MWBase::SoundManager { Ogre::ResourceGroupManager& mResourceMgr; @@ -63,9 +47,12 @@ namespace MWSound std::string mCurrentPlaylist; typedef std::pair PtrIDPair; - typedef std::map SoundMap; + typedef std::map SoundMap; SoundMap mActiveSounds; + Ogre::Vector3 mListenerPos; + Ogre::Vector3 mListenerDir; + std::string lookup(const std::string &soundId, float &volume, float &min, float &max); void streamMusicFull(const std::string& filename); @@ -82,67 +69,69 @@ namespace MWSound public: SoundManager(bool useSound); - ~SoundManager(); + virtual ~SoundManager(); - void processChangedSettings(const Settings::CategorySettingVector& settings); + virtual void processChangedSettings(const Settings::CategorySettingVector& settings); - void stopMusic(); + virtual void stopMusic(); ///< Stops music if it's playing - void streamMusic(const std::string& filename); + virtual void streamMusic(const std::string& filename); ///< Play a soundifle /// \param filename name of a sound file in "Music/" in the data directory. - void startRandomTitle(); + virtual void startRandomTitle(); ///< Starts a random track from the current playlist - bool isMusicPlaying(); + virtual bool isMusicPlaying(); ///< Returns true if music is playing - void playPlaylist(const std::string &playlist); + virtual void playPlaylist(const std::string &playlist); ///< Start playing music from the selected folder /// \param name of the folder that contains the playlist - void say(MWWorld::Ptr reference, const std::string& filename); + virtual void say(MWWorld::Ptr reference, const std::string& filename); ///< Make an actor say some text. /// \param filename name of a sound file in "Sound/" in the data directory. - void say(const std::string& filename); + virtual void say(const std::string& filename); ///< Say some text, without an actor ref /// \param filename name of a sound file in "Sound/" in the data directory. - bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const; + virtual bool sayDone(MWWorld::Ptr reference=MWWorld::Ptr()) const; ///< Is actor not speaking? - void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); + virtual void stopSay(MWWorld::Ptr reference=MWWorld::Ptr()); ///< Stop an actor speaking - SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal); + virtual MWBase::SoundPtr playSound(const std::string& soundId, float volume, float pitch, int mode=Play_Normal); ///< Play a sound, independently of 3D-position - SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, + virtual MWBase::SoundPtr playSound3D(MWWorld::Ptr reference, const std::string& soundId, float volume, float pitch, int mode=Play_Normal); ///< Play a sound from an object - void stopSound3D(MWWorld::Ptr reference, const std::string& soundId); + virtual void stopSound3D(MWWorld::Ptr reference, const std::string& soundId); ///< Stop the given object from playing the given sound, - void stopSound3D(MWWorld::Ptr reference); + virtual void stopSound3D(MWWorld::Ptr reference); ///< Stop the given object from playing all sounds. - void stopSound(const MWWorld::Ptr::CellStore *cell); + virtual void stopSound(const MWWorld::CellStore *cell); ///< Stop all sounds for the given cell. - void stopSound(const std::string& soundId); + virtual void stopSound(const std::string& soundId); ///< Stop a non-3d looping sound - bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; + virtual bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; ///< Is the given sound currently playing on the given object? - void updateObject(MWWorld::Ptr reference); + virtual void updateObject(MWWorld::Ptr reference); ///< Update the position of all sounds connected to the given object. - void update(float duration); + virtual void update(float duration); + + virtual void setListenerPosDir(const Ogre::Vector3 &pos, const Ogre::Vector3 &dir); }; } diff --git a/apps/openmw/mwworld/action.cpp b/apps/openmw/mwworld/action.cpp new file mode 100644 index 000000000..c142294bb --- /dev/null +++ b/apps/openmw/mwworld/action.cpp @@ -0,0 +1,23 @@ + +#include "action.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" + +MWWorld::Action::Action() {} + +MWWorld::Action::~Action() {} + +void MWWorld::Action::execute (const Ptr& actor) +{ + if (!mSoundId.empty()) + MWBase::Environment::get().getSoundManager()->playSound3D (actor, mSoundId, 1.0, 1.0, + MWBase::SoundManager::Play_NoTrack); + + executeImp (actor); +} + +void MWWorld::Action::setSound (const std::string& id) +{ + mSoundId = id; +} diff --git a/apps/openmw/mwworld/action.hpp b/apps/openmw/mwworld/action.hpp index d5cf12779..a00f67951 100644 --- a/apps/openmw/mwworld/action.hpp +++ b/apps/openmw/mwworld/action.hpp @@ -1,22 +1,32 @@ #ifndef GAME_MWWORLD_ACTION_H #define GAME_MWWORLD_ACTION_H +#include + namespace MWWorld { + class Ptr; + /// \brief Abstract base for actions class Action { + std::string mSoundId; + // not implemented Action (const Action& action); Action& operator= (const Action& action); + virtual void executeImp (const Ptr& actor) = 0; + public: - Action() {} + Action(); - virtual ~Action() {} + virtual ~Action(); - virtual void execute() = 0; + void execute (const Ptr& actor); + + void setSound (const std::string& id); }; } diff --git a/apps/openmw/mwworld/actionalchemy.cpp b/apps/openmw/mwworld/actionalchemy.cpp index eb91b6946..bba75bc49 100644 --- a/apps/openmw/mwworld/actionalchemy.cpp +++ b/apps/openmw/mwworld/actionalchemy.cpp @@ -1,11 +1,11 @@ #include "actionalchemy.hpp" #include "../mwbase/environment.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwbase/windowmanager.hpp" namespace MWWorld { - void ActionAlchemy::execute() + void ActionAlchemy::executeImp (const Ptr& actor) { MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Alchemy); } diff --git a/apps/openmw/mwworld/actionalchemy.hpp b/apps/openmw/mwworld/actionalchemy.hpp index 739de419b..e6d1a7976 100644 --- a/apps/openmw/mwworld/actionalchemy.hpp +++ b/apps/openmw/mwworld/actionalchemy.hpp @@ -7,8 +7,7 @@ namespace MWWorld { class ActionAlchemy : public Action { - public: - virtual void execute (); + virtual void executeImp (const Ptr& actor); }; } diff --git a/apps/openmw/mwworld/actionapply.cpp b/apps/openmw/mwworld/actionapply.cpp new file mode 100644 index 000000000..595ee6cb3 --- /dev/null +++ b/apps/openmw/mwworld/actionapply.cpp @@ -0,0 +1,28 @@ + +#include "actionapply.hpp" + +#include "class.hpp" + +namespace MWWorld +{ + ActionApply::ActionApply (const Ptr& target, const std::string& id) + : mTarget (target), mId (id) + {} + + void ActionApply::executeImp (const Ptr& actor) + { + MWWorld::Class::get (mTarget).apply (mTarget, mId, actor); + } + + + ActionApplyWithSkill::ActionApplyWithSkill (const Ptr& target, const std::string& id, + int skillIndex, int usageType) + : mTarget (target), mId (id), mSkillIndex (skillIndex), mUsageType (usageType) + {} + + void ActionApplyWithSkill::executeImp (const Ptr& actor) + { + if (MWWorld::Class::get (mTarget).apply (mTarget, mId, actor) && mUsageType!=-1) + MWWorld::Class::get (mTarget).skillUsageSucceeded (actor, mSkillIndex, mUsageType); + } +} diff --git a/apps/openmw/mwworld/actionapply.hpp b/apps/openmw/mwworld/actionapply.hpp new file mode 100644 index 000000000..523bf9373 --- /dev/null +++ b/apps/openmw/mwworld/actionapply.hpp @@ -0,0 +1,40 @@ + +#ifndef GAME_MWWORLD_ACTIONAPPLY_H +#define GAME_MWWORLD_ACTIONAPPLY_H + +#include + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionApply : public Action + { + Ptr mTarget; + std::string mId; + + virtual void executeImp (const Ptr& actor); + + public: + + ActionApply (const Ptr& target, const std::string& id); + }; + + class ActionApplyWithSkill : public Action + { + Ptr mTarget; + std::string mId; + int mSkillIndex; + int mUsageType; + + virtual void executeImp (const Ptr& actor); + + public: + + ActionApplyWithSkill (const Ptr& target, const std::string& id, + int skillIndex, int usageType); + }; +} + +#endif diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index f3bb256fd..20e0afb68 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -1,9 +1,11 @@ #include "actionequip.hpp" #include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" -#include "../mwworld/inventorystore.hpp" -#include "../mwworld/player.hpp" +#include "../mwbase/world.hpp" + +#include "inventorystore.hpp" +#include "player.hpp" +#include "class.hpp" namespace MWWorld { @@ -11,10 +13,10 @@ namespace MWWorld { } - void ActionEquip::execute () + void ActionEquip::executeImp (const Ptr& actor) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(player).getContainerStore(player)); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(player).getInventoryStore(player); // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(mObject).getEquipmentSlots(mObject); @@ -51,4 +53,3 @@ namespace MWWorld } } } - diff --git a/apps/openmw/mwworld/actionequip.hpp b/apps/openmw/mwworld/actionequip.hpp index 6cf3640f8..5685a294a 100644 --- a/apps/openmw/mwworld/actionequip.hpp +++ b/apps/openmw/mwworld/actionequip.hpp @@ -10,11 +10,11 @@ namespace MWWorld { Ptr mObject; + virtual void executeImp (const Ptr& actor); + public: /// @param item to equip ActionEquip (const Ptr& object); - - virtual void execute (); }; } diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp index dd36487dc..15a9f510d 100644 --- a/apps/openmw/mwworld/actionopen.cpp +++ b/apps/openmw/mwworld/actionopen.cpp @@ -1,20 +1,20 @@ #include "actionopen.hpp" #include "../mwbase/environment.hpp" -#include "class.hpp" -#include "world.hpp" -#include "containerstore.hpp" -#include "../mwclass/container.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwgui/container.hpp" +#include "class.hpp" +#include "containerstore.hpp" + namespace MWWorld { ActionOpen::ActionOpen (const MWWorld::Ptr& container) : mContainer (container) { mContainer = container; } - void ActionOpen::execute () + void ActionOpen::executeImp (const MWWorld::Ptr& actor) { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) return; diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp index eff26c78c..5666ff293 100644 --- a/apps/openmw/mwworld/actionopen.hpp +++ b/apps/openmw/mwworld/actionopen.hpp @@ -12,10 +12,11 @@ namespace MWWorld { Ptr mContainer; + virtual void executeImp (const MWWorld::Ptr& actor); + public: ActionOpen (const Ptr& container); ///< \param The Container the Player has activated. - virtual void execute (); }; } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index 34e95cbd0..5c6ab93c1 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -1,7 +1,8 @@ #include "actionread.hpp" #include "../mwbase/environment.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwbase/windowmanager.hpp" + #include "../mwgui/bookwindow.hpp" #include "../mwgui/scrollwindow.hpp" @@ -11,10 +12,9 @@ namespace MWWorld { } - void ActionRead::execute () + void ActionRead::executeImp (const MWWorld::Ptr& actor) { - ESMS::LiveCellRef *ref = - mObject.get(); + LiveCellRef *ref = mObject.get(); if (ref->base->data.isScroll) { @@ -28,4 +28,3 @@ namespace MWWorld } } } - diff --git a/apps/openmw/mwworld/actionread.hpp b/apps/openmw/mwworld/actionread.hpp index a4b495f79..9bb74fb88 100644 --- a/apps/openmw/mwworld/actionread.hpp +++ b/apps/openmw/mwworld/actionread.hpp @@ -10,11 +10,11 @@ namespace MWWorld { Ptr mObject; // book or scroll to read + virtual void executeImp (const MWWorld::Ptr& actor); + public: /// @param book or scroll to read ActionRead (const Ptr& object); - - virtual void execute (); }; } diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index 9cff42812..90f3c000e 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -2,17 +2,17 @@ #include "actiontake.hpp" #include "../mwbase/environment.hpp" -#include "../mwgui/window_manager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "class.hpp" -#include "world.hpp" #include "containerstore.hpp" namespace MWWorld { ActionTake::ActionTake (const MWWorld::Ptr& object) : mObject (object) {} - void ActionTake::execute() + void ActionTake::executeImp (const Ptr& actor) { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) return; diff --git a/apps/openmw/mwworld/actiontake.hpp b/apps/openmw/mwworld/actiontake.hpp index f495fc3c4..52a114acf 100644 --- a/apps/openmw/mwworld/actiontake.hpp +++ b/apps/openmw/mwworld/actiontake.hpp @@ -10,11 +10,11 @@ namespace MWWorld { MWWorld::Ptr mObject; + virtual void executeImp (const Ptr& actor); + public: ActionTake (const MWWorld::Ptr& object); - - virtual void execute(); }; } diff --git a/apps/openmw/mwworld/actiontalk.cpp b/apps/openmw/mwworld/actiontalk.cpp index a0f9d8c4c..d94cb67f4 100644 --- a/apps/openmw/mwworld/actiontalk.cpp +++ b/apps/openmw/mwworld/actiontalk.cpp @@ -2,14 +2,13 @@ #include "actiontalk.hpp" #include "../mwbase/environment.hpp" -#include "../mwgui/window_manager.hpp" -#include "../mwdialogue/dialoguemanager.hpp" +#include "../mwbase/dialoguemanager.hpp" namespace MWWorld { ActionTalk::ActionTalk (const Ptr& actor) : mActor (actor) {} - void ActionTalk::execute() + void ActionTalk::executeImp (const Ptr& actor) { MWBase::Environment::get().getDialogueManager()->startDialogue (mActor); } diff --git a/apps/openmw/mwworld/actiontalk.hpp b/apps/openmw/mwworld/actiontalk.hpp index 1b7b9b6d6..53adf9e53 100644 --- a/apps/openmw/mwworld/actiontalk.hpp +++ b/apps/openmw/mwworld/actiontalk.hpp @@ -10,12 +10,12 @@ namespace MWWorld { Ptr mActor; + virtual void executeImp (const Ptr& actor); + public: ActionTalk (const Ptr& actor); ///< \param actor The actor the player is talking to - - virtual void execute(); }; } diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 6ebbd7b7f..9c87d37ae 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -2,17 +2,16 @@ #include "actionteleport.hpp" #include "../mwbase/environment.hpp" - -#include "world.hpp" +#include "../mwbase/world.hpp" namespace MWWorld { - ActionTeleportPlayer::ActionTeleportPlayer (const std::string& cellName, + ActionTeleport::ActionTeleport (const std::string& cellName, const ESM::Position& position) : mCellName (cellName), mPosition (position) {} - void ActionTeleportPlayer::execute() + void ActionTeleport::executeImp (const Ptr& actor) { if (mCellName.empty()) MWBase::Environment::get().getWorld()->changeToExteriorCell (mPosition); diff --git a/apps/openmw/mwworld/actionteleport.hpp b/apps/openmw/mwworld/actionteleport.hpp index 00efdc876..a13cb61b2 100644 --- a/apps/openmw/mwworld/actionteleport.hpp +++ b/apps/openmw/mwworld/actionteleport.hpp @@ -9,17 +9,17 @@ namespace MWWorld { - class ActionTeleportPlayer : public Action + class ActionTeleport : public Action { std::string mCellName; ESM::Position mPosition; + virtual void executeImp (const Ptr& actor); + public: - ActionTeleportPlayer (const std::string& cellName, const ESM::Position& position); + ActionTeleport (const std::string& cellName, const ESM::Position& position); ///< If cellName is empty, an exterior cell is asumed. - - virtual void execute(); }; } diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 990a4cc4a..822aa78d6 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -1,10 +1,10 @@ #include "cells.hpp" -#include +#include -#include +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" -#include "world.hpp" #include "class.hpp" #include "containerstore.hpp" @@ -39,7 +39,7 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell) void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) { - for (ESMS::CellRefList::List::iterator iter ( + for (CellRefList::List::iterator iter ( cellStore.containers.list.begin()); iter!=cellStore.containers.list.end(); ++iter) { @@ -49,7 +49,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) iter->base->inventory, mStore); } - for (ESMS::CellRefList::List::iterator iter ( + for (CellRefList::List::iterator iter ( cellStore.creatures.list.begin()); iter!=cellStore.creatures.list.end(); ++iter) { @@ -59,7 +59,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) iter->base->inventory, mStore); } - for (ESMS::CellRefList::List::iterator iter ( + for (CellRefList::List::iterator iter ( cellStore.npcs.list.begin()); iter!=cellStore.npcs.list.end(); ++iter) { @@ -70,8 +70,26 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) } } -MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world) -: mStore (store), mReader (reader), mWorld (world) {} +MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, Ptr::CellStore& cellStore) +{ + Ptr ptr = getPtr (name, cellStore); + + if (!ptr.isEmpty()) + { + mIdCache[mIdCacheIndex].first = name; + mIdCache[mIdCacheIndex].second = &cellStore; + if (++mIdCacheIndex>=mIdCache.size()) + mIdCacheIndex = 0; + } + + return ptr; +} + +MWWorld::Cells::Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader) +: mStore (store), mReader (reader), + mIdCache (20, std::pair ("", (Ptr::CellStore*)0)), /// \todo make cache size configurable + mIdCacheIndex (0) +{} MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) { @@ -93,11 +111,11 @@ MWWorld::Ptr::CellStore *MWWorld::Cells::getExterior (int x, int y) record.water = 0; record.mapColor = 0; - cell = mWorld.createRecord (record); + cell = MWBase::Environment::get().getWorld()->createRecord (record); } result = mExteriors.insert (std::make_pair ( - std::make_pair (x, y), Ptr::CellStore (cell))).first; + std::make_pair (x, y), CellStore (cell))).first; } if (result->second.mState!=Ptr::CellStore::State_Loaded) @@ -149,85 +167,99 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce else return Ptr(); } + MWWorld::Ptr ptr; - if (ESMS::LiveCellRef *ref = cell.activators.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.activators.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.potions.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.potions.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.appas.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.appas.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.armors.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.armors.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.books.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.books.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.clothes.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.clothes.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.containers.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.containers.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.creatures.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.creatures.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.doors.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.doors.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.ingreds.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.ingreds.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.creatureLists.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.creatureLists.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.itemLists.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.itemLists.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.lights.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.lights.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.lockpicks.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.lockpicks.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.miscItems.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.miscItems.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.npcs.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.npcs.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.probes.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.probes.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.repairs.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.repairs.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.statics.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.statics.find (name)) + ptr = Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = cell.weapons.find (name)) - return Ptr (ref, &cell); + if (MWWorld::LiveCellRef *ref = cell.weapons.find (name)) + ptr = Ptr (ref, &cell); + if (!ptr.isEmpty() && ptr.getRefData().getCount() > 0) { + return ptr; + } return Ptr(); } MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) { - // First check cells that are already listed + // First check the cache + for (std::vector >::iterator iter (mIdCache.begin()); + iter!=mIdCache.end(); ++iter) + if (iter->first==name && iter->second) + { + Ptr ptr = getPtr (name, *iter->second); + if (!ptr.isEmpty()) + return ptr; + } + + // Then check cells that are already listed for (std::map::iterator iter = mInteriors.begin(); iter!=mInteriors.end(); ++iter) { - Ptr ptr = getPtr (name, iter->second); + Ptr ptr = getPtrAndCache (name, iter->second); if (!ptr.isEmpty()) - return ptr; + return ptr; } for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); iter!=mExteriors.end(); ++iter) { - Ptr ptr = getPtr (name, iter->second); + Ptr ptr = getPtrAndCache (name, iter->second); if (!ptr.isEmpty()) return ptr; } @@ -238,7 +270,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) { Ptr::CellStore *cellStore = getCellStore (iter->second); - Ptr ptr = getPtr (name, *cellStore); + Ptr ptr = getPtrAndCache (name, *cellStore); if (!ptr.isEmpty()) return ptr; @@ -249,7 +281,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) { Ptr::CellStore *cellStore = getCellStore (iter->second); - Ptr ptr = getPtr (name, *cellStore); + Ptr ptr = getPtrAndCache (name, *cellStore); if (!ptr.isEmpty()) return ptr; diff --git a/apps/openmw/mwworld/cells.hpp b/apps/openmw/mwworld/cells.hpp index 42aa1050c..3e1383166 100644 --- a/apps/openmw/mwworld/cells.hpp +++ b/apps/openmw/mwworld/cells.hpp @@ -18,35 +18,36 @@ namespace ESM namespace MWWorld { - class World; - /// \brief Cell container class Cells { const ESMS::ESMStore& mStore; ESM::ESMReader& mReader; - std::map mInteriors; - std::map, Ptr::CellStore> mExteriors; - MWWorld::World& mWorld; + std::map mInteriors; + std::map, CellStore> mExteriors; + std::vector > mIdCache; + std::size_t mIdCacheIndex; Cells (const Cells&); Cells& operator= (const Cells&); - Ptr::CellStore *getCellStore (const ESM::Cell *cell); + CellStore *getCellStore (const ESM::Cell *cell); - void fillContainers (Ptr::CellStore& cellStore); + void fillContainers (CellStore& cellStore); + + Ptr getPtrAndCache (const std::string& name, CellStore& cellStore); public: - Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader, MWWorld::World& world); + Cells (const ESMS::ESMStore& store, ESM::ESMReader& reader); ///< \todo pass the dynamic part of the ESMStore isntead (once it is written) of the whole /// world - Ptr::CellStore *getExterior (int x, int y); + CellStore *getExterior (int x, int y); - Ptr::CellStore *getInterior (const std::string& name); + CellStore *getInterior (const std::string& name); - Ptr getPtr (const std::string& name, Ptr::CellStore& cellStore); + Ptr getPtr (const std::string& name, CellStore& cellStore); Ptr getPtr (const std::string& name); }; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp new file mode 100644 index 000000000..eceb5ddc1 --- /dev/null +++ b/apps/openmw/mwworld/cellstore.cpp @@ -0,0 +1,128 @@ +#include "cellstore.hpp" + +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "ptr.hpp" + +namespace MWWorld +{ + CellStore::CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded) + { + mWaterLevel = cell->water; + } + + void CellStore::load (const ESMS::ESMStore &store, ESM::ESMReader &esm) + { + if (mState!=State_Loaded) + { + if (mState==State_Preloaded) + mIds.clear(); + + std::cout << "loading cell " << cell->getDescription() << std::endl; + + loadRefs (store, esm); + + mState = State_Loaded; + } + } + + void CellStore::preload (const ESMS::ESMStore &store, ESM::ESMReader &esm) + { + if (mState==State_Unloaded) + { + listRefs (store, esm); + + mState = State_Preloaded; + } + } + + void CellStore::listRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm) + { + assert (cell); + + if (cell->context.filename.empty()) + return; // this is a dynamically generated cell -> skipping. + + // Reopen the ESM reader and seek to the right position. + cell->restore (esm); + + ESM::CellRef ref; + + // Get each reference in turn + while (cell->getNextRef (esm, ref)) + { + std::string lowerCase; + + std::transform (ref.refID.begin(), ref.refID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + mIds.push_back (lowerCase); + } + + std::sort (mIds.begin(), mIds.end()); + } + + void CellStore::loadRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm) + { + assert (cell); + + if (cell->context.filename.empty()) + return; // this is a dynamically generated cell -> skipping. + + // Reopen the ESM reader and seek to the right position. + cell->restore(esm); + + ESM::CellRef ref; + + // Get each reference in turn + while(cell->getNextRef(esm, ref)) + { + std::string lowerCase; + + std::transform (ref.refID.begin(), ref.refID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + int rec = store.find(ref.refID); + + ref.refID = lowerCase; + + /* We can optimize this further by storing the pointer to the + record itself in store.all, so that we don't need to look it + up again here. However, never optimize. There are infinite + opportunities to do that later. + */ + switch(rec) + { + case ESM::REC_ACTI: activators.find(ref, store.activators); break; + case ESM::REC_ALCH: potions.find(ref, store.potions); break; + case ESM::REC_APPA: appas.find(ref, store.appas); break; + case ESM::REC_ARMO: armors.find(ref, store.armors); break; + case ESM::REC_BOOK: books.find(ref, store.books); break; + case ESM::REC_CLOT: clothes.find(ref, store.clothes); break; + case ESM::REC_CONT: containers.find(ref, store.containers); break; + case ESM::REC_CREA: creatures.find(ref, store.creatures); break; + case ESM::REC_DOOR: doors.find(ref, store.doors); break; + case ESM::REC_INGR: ingreds.find(ref, store.ingreds); break; + case ESM::REC_LEVC: creatureLists.find(ref, store.creatureLists); break; + case ESM::REC_LEVI: itemLists.find(ref, store.itemLists); break; + case ESM::REC_LIGH: lights.find(ref, store.lights); break; + case ESM::REC_LOCK: lockpicks.find(ref, store.lockpicks); break; + case ESM::REC_MISC: miscItems.find(ref, store.miscItems); break; + case ESM::REC_NPC_: npcs.find(ref, store.npcs); break; + case ESM::REC_PROB: probes.find(ref, store.probes); break; + case ESM::REC_REPA: repairs.find(ref, store.repairs); break; + case ESM::REC_STAT: statics.find(ref, store.statics); break; + case ESM::REC_WEAP: weapons.find(ref, store.weapons); break; + + case 0: std::cout << "Cell reference " + ref.refID + " not found!\n"; break; + default: + std::cout << "WARNING: Ignoring reference '" << ref.refID << "' of unhandled type\n"; + } + } + } +} diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp new file mode 100644 index 000000000..3ec4a2e78 --- /dev/null +++ b/apps/openmw/mwworld/cellstore.hpp @@ -0,0 +1,192 @@ +#ifndef GAME_MWWORLD_CELLSTORE_H +#define GAME_MWWORLD_CELLSTORE_H + +#include + +#include +#include + +#include "refdata.hpp" + +namespace ESMS +{ + struct ESMStore; +} + +namespace MWWorld +{ + class Ptr; + + /// A reference to one object (of any type) in a cell. + /// + /// Constructing this with a CellRef instance in the constructor means that + /// in practice (where D is RefData) the possibly mutable data is copied + /// across to mData. If later adding data (such as position) to CellRef + /// this would have to be manually copied across. + template + struct LiveCellRef + { + LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) : base(b), ref(cref), + mData(ref) {} + + + LiveCellRef(const X* b = NULL) : base(b), mData(ref) {} + + // The object that this instance is based on. + const X* base; + + /* Information about this instance, such as 3D location and + rotation and individual type-dependent data. + */ + ESM::CellRef ref; + + /// runtime-data + RefData mData; + }; + + /// A list of cell references + template + struct CellRefList + { + typedef LiveCellRef LiveRef; + typedef std::list List; + List list; + + // Search for the given reference in the given reclist from + // ESMStore. Insert the reference into the list if a match is + // found. If not, throw an exception. + template + void find(ESM::CellRef &ref, const Y& recList) + { + const X* obj = recList.find(ref.refID); + if(obj == NULL) + throw std::runtime_error("Error resolving cell reference " + ref.refID); + + list.push_back(LiveRef(ref, obj)); + } + + LiveRef *find (const std::string& name) + { + for (typename std::list::iterator iter (list.begin()); iter!=list.end(); ++iter) + { + if (iter->mData.getCount() > 0 && iter->ref.refID == name) + return &*iter; + } + + return 0; + } + + LiveRef &insert(const LiveRef &item) { + list.push_back(item); + return list.back(); + } + }; + + /// A storage struct for one single cell reference. + class CellStore + { + public: + + enum State + { + State_Unloaded, State_Preloaded, State_Loaded + }; + + CellStore (const ESM::Cell *cell_); + + const ESM::Cell *cell; + State mState; + std::vector mIds; + + float mWaterLevel; + + // Lists for each individual object type + CellRefList activators; + CellRefList potions; + CellRefList appas; + CellRefList armors; + CellRefList books; + CellRefList clothes; + CellRefList containers; + CellRefList creatures; + CellRefList doors; + CellRefList ingreds; + CellRefList creatureLists; + CellRefList itemLists; + CellRefList lights; + CellRefList lockpicks; + CellRefList miscItems; + CellRefList npcs; + CellRefList probes; + CellRefList repairs; + CellRefList statics; + CellRefList weapons; + + void load (const ESMS::ESMStore &store, ESM::ESMReader &esm); + + void preload (const ESMS::ESMStore &store, ESM::ESMReader &esm); + + /// Call functor (ref) for each reference. functor must return a bool. Returning + /// false will abort the iteration. + /// \return Iteration completed? + template + bool forEach (Functor& functor) + { + return + forEachImp (functor, activators) && + forEachImp (functor, potions) && + forEachImp (functor, appas) && + forEachImp (functor, armors) && + forEachImp (functor, books) && + forEachImp (functor, clothes) && + forEachImp (functor, containers) && + forEachImp (functor, creatures) && + forEachImp (functor, doors) && + forEachImp (functor, ingreds) && + forEachImp (functor, creatureLists) && + forEachImp (functor, itemLists) && + forEachImp (functor, lights) && + forEachImp (functor, lockpicks) && + forEachImp (functor, miscItems) && + forEachImp (functor, npcs) && + forEachImp (functor, probes) && + forEachImp (functor, repairs) && + forEachImp (functor, statics) && + forEachImp (functor, weapons); + } + + bool operator==(const CellStore &cell) { + return this->cell->name == cell.cell->name && + this->cell->data.gridX == cell.cell->data.gridX && + this->cell->data.gridY == cell.cell->data.gridY; + } + + bool operator!=(const CellStore &cell) { + return !(*this == cell); + } + + bool isExterior() const { + return cell->isExterior(); + } + + private: + + template + bool forEachImp (Functor& functor, List& list) + { + for (typename List::List::iterator iter (list.list.begin()); iter!=list.list.end(); + ++iter) + if (!functor (iter->ref, iter->mData)) + return false; + + return true; + } + + /// Run through references and store IDs + void listRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm); + + void loadRefs(const ESMS::ESMStore &store, ESM::ESMReader &esm); + }; +} + +#endif diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index fe39406fe..5267e368d 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -5,10 +5,15 @@ #include +#include + #include "ptr.hpp" +#include "refdata.hpp" #include "nullaction.hpp" #include "containerstore.hpp" +#include "../mwgui/tooltips.hpp" + namespace MWWorld { std::map > Class::sClasses; @@ -32,6 +37,16 @@ namespace MWWorld } + bool Class::apply (const MWWorld::Ptr& ptr, const std::string& id, const MWWorld::Ptr& actor) const + { + return false; + } + + void Class::skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const + { + throw std::runtime_error ("class does not represent an actor"); + } + MWMechanics::CreatureStats& Class::getCreatureStats (const Ptr& ptr) const { throw std::runtime_error ("class does not have creature stats"); @@ -192,4 +207,40 @@ namespace MWWorld { return ""; } + + void Class::adjustScale(const MWWorld::Ptr& ptr,float& scale) const + { + } + + void Class::adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const + { + } + + std::string Class::getModel(const MWWorld::Ptr &ptr) const + { + return ""; + } + + MWWorld::Ptr + Class::copyToCellImpl(const Ptr &ptr, CellStore &cell) const + { + throw std::runtime_error("unable to move class to cell"); + } + + MWWorld::Ptr + Class::copyToCell(const Ptr &ptr, CellStore &cell) const + { + Ptr newPtr = copyToCellImpl(ptr, cell); + + return newPtr; + } + + MWWorld::Ptr + Class::copyToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos) const + { + Ptr newPtr = copyToCell(ptr, cell); + newPtr.getRefData().getPosition() = pos; + + return newPtr; + } } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 46781d516..3c3b0e34b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -8,11 +8,6 @@ #include #include "action.hpp" -#include "refdata.hpp" -#include "physicssystem.hpp" - -#include "../mwrender/renderinginterface.hpp" -#include "../mwgui/tooltips.hpp" namespace Ogre { @@ -21,21 +16,33 @@ namespace Ogre namespace MWRender { - class CellRenderImp; + class RenderingInterface; } namespace MWMechanics { - struct CreatureStats; - struct NpcStats; + class CreatureStats; + class NpcStats; struct Movement; } +namespace MWGui +{ + struct ToolTipInfo; +} + +namespace ESM +{ + struct Position; +} + namespace MWWorld { class Ptr; class ContainerStore; class InventoryStore; + class PhysicsSystem; + class CellStore; /// \brief Base class for referenceable esm records class Class @@ -50,6 +57,8 @@ namespace MWWorld Class(); + virtual Ptr copyToCellImpl(const Ptr &ptr, CellStore &cell) const; + public: /// NPC-stances. @@ -164,6 +173,19 @@ namespace MWWorld /// effects). Throws an exception, if the object can't hold other objects. /// (default implementation: throws an exception) + virtual bool apply (const MWWorld::Ptr& ptr, const std::string& id, + const MWWorld::Ptr& actor) const; + ///< Apply \a id on \a ptr. + /// \param actor Actor that is resposible for the ID being applied to \a ptr. + /// \return Any effect? + /// + /// (default implementation: ignore and return false) + + virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const; + ///< Inform actor \a ptr that a skill use has succeeded. + /// + /// (default implementations: throws an exception) + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. @@ -186,6 +208,23 @@ namespace MWWorld virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) + + virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const; + + virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const; + + virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual Ptr + copyToCell(const Ptr &ptr, CellStore &cell) const; + + virtual Ptr + copyToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos) const; + + virtual bool + isActor() const { + return false; + } }; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 3304d0e6d..1d473246c 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -5,12 +5,12 @@ #include #include -#include +#include #include #include "../mwbase/environment.hpp" -#include "../mwworld/world.hpp" +#include "../mwbase/world.hpp" #include "manualref.hpp" #include "refdata.hpp" @@ -19,11 +19,11 @@ namespace { template - float getTotalWeight (const ESMS::CellRefList& cellRefList) + float getTotalWeight (const MWWorld::CellRefList& cellRefList) { float sum = 0; - for (typename ESMS::CellRefList::List::const_iterator iter ( + for (typename MWWorld::CellRefList::List::const_iterator iter ( cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) @@ -78,7 +78,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) if (MWWorld::Class::get(ptr).getName(ptr) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) { - ESMS::LiveCellRef *gold = + MWWorld::LiveCellRef *gold = ptr.get(); if (compare_string_ci(gold->ref.refID, "gold_001") @@ -281,29 +281,29 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor ++*this; } -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Potion), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mPotion(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Apparatus), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mApparatus(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Armor), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mArmor(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Book), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mBook(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Clothing), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mClothing(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Probe), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mProbe(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Repair), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mRepair(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Weapon), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mWeapon(iterator){} void MWWorld::ContainerStoreIterator::incType() diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 15b553f9d..ae27fad3d 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -3,9 +3,6 @@ #include -#include - -#include "refdata.hpp" #include "ptr.hpp" namespace ESM @@ -40,18 +37,18 @@ namespace MWWorld private: - ESMS::CellRefList potions; - ESMS::CellRefList appas; - ESMS::CellRefList armors; - ESMS::CellRefList books; - ESMS::CellRefList clothes; - ESMS::CellRefList ingreds; - ESMS::CellRefList lights; - ESMS::CellRefList lockpicks; - ESMS::CellRefList miscItems; - ESMS::CellRefList probes; - ESMS::CellRefList repairs; - ESMS::CellRefList weapons; + MWWorld::CellRefList potions; + MWWorld::CellRefList appas; + MWWorld::CellRefList armors; + MWWorld::CellRefList books; + MWWorld::CellRefList clothes; + MWWorld::CellRefList ingreds; + MWWorld::CellRefList lights; + MWWorld::CellRefList lockpicks; + MWWorld::CellRefList miscItems; + MWWorld::CellRefList probes; + MWWorld::CellRefList repairs; + MWWorld::CellRefList weapons; int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; @@ -122,18 +119,18 @@ namespace MWWorld ContainerStore *mContainer; mutable Ptr mPtr; - ESMS::CellRefList::List::iterator mPotion; - ESMS::CellRefList::List::iterator mApparatus; - ESMS::CellRefList::List::iterator mArmor; - ESMS::CellRefList::List::iterator mBook; - ESMS::CellRefList::List::iterator mClothing; - ESMS::CellRefList::List::iterator mIngredient; - ESMS::CellRefList::List::iterator mLight; - ESMS::CellRefList::List::iterator mLockpick; - ESMS::CellRefList::List::iterator mMiscellaneous; - ESMS::CellRefList::List::iterator mProbe; - ESMS::CellRefList::List::iterator mRepair; - ESMS::CellRefList::List::iterator mWeapon; + MWWorld::CellRefList::List::iterator mPotion; + MWWorld::CellRefList::List::iterator mApparatus; + MWWorld::CellRefList::List::iterator mArmor; + MWWorld::CellRefList::List::iterator mBook; + MWWorld::CellRefList::List::iterator mClothing; + MWWorld::CellRefList::List::iterator mIngredient; + MWWorld::CellRefList::List::iterator mLight; + MWWorld::CellRefList::List::iterator mLockpick; + MWWorld::CellRefList::List::iterator mMiscellaneous; + MWWorld::CellRefList::List::iterator mProbe; + MWWorld::CellRefList::List::iterator mRepair; + MWWorld::CellRefList::List::iterator mWeapon; private: @@ -144,18 +141,18 @@ namespace MWWorld ///< Begin-iterator // construct iterator using a CellRefList iterator - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); void incType(); diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6df73004b..9e4381f07 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,9 +6,10 @@ #include -#include "../mwbase/environment.hpp" +#include -#include "../mwworld/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" @@ -147,7 +148,7 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) bool use = false; if (slots.at (*iter2)==end()) - use = true; // slot was empty before -> skill all further checks + use = true; // slot was empty before -> skip all further checks else { Ptr old = *slots.at (*iter2); @@ -158,12 +159,14 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) int oldSkill = MWWorld::Class::get (old).getEquipmentSkill (old); - if (testSkill!=-1 || oldSkill!=-1 || testSkill!=oldSkill) + if (testSkill!=-1 && oldSkill==-1) + use = true; + else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill) { - if (stats.mSkill[oldSkill].getModified()>stats.mSkill[testSkill].getModified()) + if (stats.getSkill (oldSkill).getModified()>stats.getSkill (testSkill).getModified()) continue; // rejected, because old item better matched the NPC's skills. - if (stats.mSkill[oldSkill].getModified() + +#include "cellstore.hpp" + namespace { template void listCellScripts (MWWorld::LocalScripts& localScripts, - ESMS::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) + MWWorld::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) { - for (typename ESMS::CellRefList::List::iterator iter ( + for (typename MWWorld::CellRefList::List::iterator iter ( cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) { diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 1ea2cf4d5..78f65e356 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -13,6 +13,8 @@ namespace ESMS namespace MWWorld { + class CellStore; + /// \brief List of active local scripts class LocalScripts { @@ -41,13 +43,13 @@ namespace MWWorld void add (const std::string& scriptName, const Ptr& ptr); ///< Add script to collection of active local scripts. - void addCell (Ptr::CellStore *cell); + void addCell (CellStore *cell); ///< Add all local scripts in a cell. void clear(); ///< Clear active local scripts collection. - void clearCell (Ptr::CellStore *cell); + void clearCell (CellStore *cell); ///< Remove all scripts belonging to \a cell. void remove (const Ptr& ptr); diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index f8bc7d983..6044ac8d5 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -3,10 +3,10 @@ #include -#include #include #include "ptr.hpp" +#include "cellstore.hpp" namespace MWWorld { @@ -24,11 +24,11 @@ namespace MWWorld { if (const T *instance = list.search (name)) { - ESMS::LiveCellRef ref; + LiveCellRef ref; ref.base = instance; mRef = ref; - mPtr = Ptr (&boost::any_cast&> (mRef), 0); + mPtr = Ptr (&boost::any_cast&> (mRef), 0); return true; } @@ -41,11 +41,11 @@ namespace MWWorld { if (const T *instance = list.search (name)) { - ESMS::LiveCellRef ref; + LiveCellRef ref; ref.base = instance; mRef = ref; - mPtr = Ptr (&boost::any_cast&> (mRef), 0); + mPtr = Ptr (&boost::any_cast&> (mRef), 0); return true; } diff --git a/apps/openmw/mwworld/nullaction.hpp b/apps/openmw/mwworld/nullaction.hpp index c8e3368e4..7ef8b4a06 100644 --- a/apps/openmw/mwworld/nullaction.hpp +++ b/apps/openmw/mwworld/nullaction.hpp @@ -8,9 +8,7 @@ namespace MWWorld /// \brief Action: do nothing class NullAction : public Action { - public: - - virtual void execute() {} + virtual void executeImp (const Ptr& actor) {} }; } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7c1ff31b4..45cfdd123 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -1,18 +1,20 @@ +#include "physicssystem.hpp" + #include -#include "physicssystem.hpp" -#include "../mwworld/ptr.hpp" -#include "../mwworld/world.hpp" // FIXME +#include +#include +#include +#include +#include +#include + #include -#include "OgreRoot.h" -#include "OgreRenderWindow.h" -#include "OgreSceneManager.h" -#include "OgreViewport.h" -#include "OgreCamera.h" -#include "OgreTextureManager.h" - +#include "../mwbase/world.hpp" // FIXME +#include "ptr.hpp" +#include "class.hpp" using namespace Ogre; namespace MWWorld @@ -120,6 +122,22 @@ namespace MWWorld return !(result.first == ""); } + std::pair + PhysicsSystem::castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len) + { + Ogre::Ray ray = Ogre::Ray(orig, dir); + Ogre::Vector3 to = ray.getPoint(len); + + btVector3 btFrom = btVector3(orig.x, orig.y, orig.z); + btVector3 btTo = btVector3(to.x, to.y, to.z); + + std::pair test = mEngine->rayTest(btFrom, btTo); + if (test.first == "") { + return std::make_pair(false, Ogre::Vector3()); + } + return std::make_pair(true, ray.getPoint(len * test.second)); + } + std::pair PhysicsSystem::castRay(float mouseX, float mouseY) { Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( @@ -164,9 +182,6 @@ namespace MWWorld for (std::vector >::const_iterator iter (actors.begin()); iter!=actors.end(); ++iter) { - OEngine::Physic::PhysicActor* act = mEngine->getCharacter(iter->first); - //if(iter->first == "player") - // std::cout << "This is player\n"; //dirty stuff to get the camera orientation. Must be changed! Ogre::SceneNode *sceneNode = mRender.getScene()->getSceneNode (iter->first); @@ -176,46 +191,27 @@ namespace MWWorld Ogre::Quaternion yawQuat = yawNode->getOrientation(); Ogre::Quaternion pitchQuat = pitchNode->getOrientation(); - // unused - //Ogre::Quaternion both = yawQuat * pitchQuat; + playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); - playerphysics->ps.viewangles.z = 0; + playerphysics->ps.viewangles.y = yawQuat.getYaw().valueDegrees() *-1 + 90; - if(mFreeFly) - { - Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); - pm_ref.rightmove = -dir1.x; - pm_ref.forwardmove = dir1.z; - pm_ref.upmove = dir1.y; + Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); - - //std::cout << "Current angle" << yawQuat.getYaw().valueDegrees() - 90<< "\n"; - //playerphysics->ps.viewangles.x = pitchQuat.getPitch().valueDegrees(); - //std::cout << "Pitch: " << yawQuat.getPitch() << "Yaw:" << yawQuat.getYaw() << "Roll: " << yawQuat.getRoll() << "\n"; - dir = 0.07*(yawQuat*pitchQuat*dir1); - } - else - { - - Ogre::Quaternion quat = yawNode->getOrientation(); - Ogre::Vector3 dir1(iter->second.x,iter->second.z,-iter->second.y); - - pm_ref.rightmove = -dir1.x; - pm_ref.forwardmove = dir1.z; - pm_ref.upmove = dir1.y; + pm_ref.rightmove = -iter->second.x; + pm_ref.forwardmove = -iter->second.y; + pm_ref.upmove = iter->second.z; - dir = 0.025*(quat*dir1); - } - - - //set the walk direction - act->setWalkDirection(btVector3(dir.x,-dir.z,dir.y)); } + + + + + mEngine->stepSimulation(dt); } @@ -233,10 +229,6 @@ namespace MWWorld if(it->first == "player"){ coord = playerphysics->ps.origin; - //std::cout << "ZCoord: " << coord.z << "\n"; - //std::cout << "Coord" << coord << "\n"; - //coord = Ogre::Vector3(coord.x, coord.z, coord.y); //x, z, -y - } @@ -261,6 +253,7 @@ namespace MWWorld void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh, const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position) { + handleToMesh[handle] = mesh; OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle,scale); mEngine->addRigidBody(body); btTransform tr; @@ -313,17 +306,27 @@ namespace MWWorld void PhysicsSystem::rotateObject (const std::string& handle, const Ogre::Quaternion& rotation) { - if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) + if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { - // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow - // start positions others than 0, 0, 0 act->setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); } + if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) + { + body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); + } } void PhysicsSystem::scaleObject (const std::string& handle, float scale) { + if(handleToMesh.find(handle) != handleToMesh.end()) + { + btTransform transform = mEngine->getRigidBody(handle)->getWorldTransform(); + removeObject(handle); + Ogre::Quaternion quat = Ogre::Quaternion(transform.getRotation().getW(), transform.getRotation().getX(), transform.getRotation().getY(), transform.getRotation().getZ()); + Ogre::Vector3 vec = Ogre::Vector3(transform.getOrigin().getX(), transform.getOrigin().getY(), transform.getOrigin().getZ()); + addObject(handle, handleToMesh[handle], quat, scale, vec); + } } bool PhysicsSystem::toggleCollisionMode() @@ -362,21 +365,41 @@ namespace MWWorld throw std::logic_error ("can't find player"); } - void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ + void PhysicsSystem::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string model){ - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - // unused - //Ogre::Vector3 objPos = node->getPosition(); + addObject( + node->getName(), + model, + node->getOrientation(), + node->getScale().x, + node->getPosition()); + } - addObject (node->getName(), model, node->getOrientation(), - node->getScale().x, node->getPosition()); - } + void PhysicsSystem::insertActorPhysics(const MWWorld::Ptr& ptr, const std::string model){ + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + addActor (node->getName(), model, node->getPosition()); + } - void PhysicsSystem::insertActorPhysics(const MWWorld::Ptr& ptr, const std::string model){ - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - // std::cout << "Adding node with name" << node->getName(); - addActor (node->getName(), model, node->getPosition()); - } + bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) + { + std::string model = MWWorld::Class::get(ptr).getModel(ptr); + if (model.empty()) { + return false; + } + btVector3 btMin, btMax; + float scale = ptr.getCellRef().scale; + mEngine->getObjectAABB(model, scale, btMin, btMax); + min.x = btMin.x(); + min.y = btMin.y(); + min.z = btMin.z(); + + max.x = btMax.x(); + max.y = btMax.y(); + max.z = btMax.z(); + + return true; + } } diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 1a8bd87ae..e42fa536b 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -1,9 +1,7 @@ #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H -#include #include -#include #include "ptr.hpp" #include @@ -56,6 +54,9 @@ namespace MWWorld // cast ray, return true if it hit something bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to); + std::pair + castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); + std::pair castRay(float mouseX, float mouseY); ///< cast ray from the mouse, return true if it hit something and the first result (in OGRE coordinates) @@ -67,11 +68,14 @@ namespace MWWorld void setCurrentWater(bool hasWater, int waterHeight); + bool getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max); + private: OEngine::Render::OgreRenderer &mRender; OEngine::Physic::PhysicEngine* mEngine; bool mFreeFly; playerMove* playerphysics; + std::map handleToMesh; PhysicsSystem (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 91b030d1c..0f05ae24d 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,18 +1,20 @@ #include "player.hpp" -#include "../mwrender/player.hpp" +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" -#include "world.hpp" #include "class.hpp" namespace MWWorld { - Player::Player (MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world) : - mCellStore (0), mRenderer (renderer), mWorld (world), mClass (0), + Player::Player (const ESM::NPC *player, const MWBase::World& world) : + mCellStore (0), mClass (0), mAutoMove (false), mForwardBackward (0) { mPlayer.base = player; @@ -24,7 +26,6 @@ namespace MWWorld float* playerPos = mPlayer.mData.getPosition().pos; playerPos[0] = playerPos[1] = playerPos[2] = 0; - mPlayer.mData.setBaseNode(renderer->getNode()); /// \todo Do not make a copy of classes defined in esm/p records. mClass = new ESM::Class (*world.getStore().classes.find (player->cls)); } @@ -34,17 +35,6 @@ namespace MWWorld delete mClass; } - void Player::setPos(float x, float y, float z) - { - /// \todo This fcuntion should be removed during the mwrender-refactoring. - mWorld.moveObject (getPlayer(), x, y, z); - } - - void Player::setRot(float x, float y, float z) - { - mRenderer->setRot(x, y, z); - } - void Player::setClass (const ESM::Class& class_) { ESM::Class *new_class = new ESM::Class (class_); @@ -52,10 +42,10 @@ namespace MWWorld mClass = new_class; } - void Player::setDrawState(const DrawState& value) + void Player::setDrawState (MWMechanics::DrawState_ state) { MWWorld::Ptr ptr = getPlayer(); - MWWorld::Class::get(ptr).getNpcStats(ptr).mDrawState = value; + MWWorld::Class::get(ptr).getNpcStats(ptr).setDrawState (state); } void Player::setAutoMove (bool enable) @@ -90,14 +80,13 @@ namespace MWWorld MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; } - void Player::setUpDown(int value) - { - MWWorld::Ptr ptr = getPlayer(); - + void Player::setUpDown(int value) + { + MWWorld::Ptr ptr = getPlayer(); MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value; - } + } void Player::toggleRunning() { @@ -108,10 +97,10 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); } - DrawState Player::getDrawState() + MWMechanics::DrawState_ Player::getDrawState() { MWWorld::Ptr ptr = getPlayer(); - return MWWorld::Class::get(ptr).getNpcStats(ptr).mDrawState; + return MWWorld::Class::get(ptr).getNpcStats(ptr).getDrawState(); } } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index a5c5ff308..68df2ec6d 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -3,29 +3,26 @@ #include "OgreCamera.h" -#include - +#include "../mwworld/cellstore.hpp" #include "../mwworld/refdata.hpp" #include "../mwworld/ptr.hpp" #include "../mwmechanics/drawstate.hpp" -namespace MWRender +namespace MWBase { - class Player; + class World; } namespace MWWorld { - class World; + class CellStore; /// \brief NPC object representing the player and additional player data - class Player + class Player { - ESMS::LiveCellRef mPlayer; - MWWorld::Ptr::CellStore *mCellStore; - MWRender::Player *mRenderer; - MWWorld::World& mWorld; + LiveCellRef mPlayer; + MWWorld::CellStore *mCellStore; std::string mName; bool mMale; std::string mRace; @@ -35,17 +32,11 @@ namespace MWWorld int mForwardBackward; public: - Player(MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world); + Player(const ESM::NPC *player, const MWBase::World& world); ~Player(); - /// Set the player position. Uses Morrowind coordinates. - void setPos(float x, float y, float z); - - /// Set where the player is looking at. Uses Morrowind (euler) angles - void setRot(float x, float y, float z); - - void setCell (MWWorld::Ptr::CellStore *cellStore) + void setCell (MWWorld::CellStore *cellStore) { mCellStore = cellStore; } @@ -56,8 +47,6 @@ namespace MWWorld return ptr; } - MWRender::Player *getRenderer() { return mRenderer; } - void setName (const std::string& name) { mName = name; @@ -80,7 +69,7 @@ namespace MWWorld void setClass (const ESM::Class& class_); - void setDrawState(const DrawState& state); + void setDrawState (MWMechanics::DrawState_ state); std::string getName() const { @@ -112,14 +101,14 @@ namespace MWWorld return mAutoMove; } - DrawState getDrawState(); + MWMechanics::DrawState_ getDrawState(); /// \todo constness void setAutoMove (bool enable); void setLeftRight (int value); void setForwardBackward (int value); - void setUpDown(int value); + void setUpDown(int value); void toggleRunning(); }; diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 4cf3e98da..f74fdd3ef 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -1,15 +1,9 @@ #ifndef GAME_MWWORLD_PTR_H #define GAME_MWWORLD_PTR_H -#include - #include -#include - -#include - -#include "refdata.hpp" +#include "cellstore.hpp" namespace MWWorld { @@ -21,7 +15,8 @@ namespace MWWorld { public: - typedef ESMS::CellStore CellStore; + typedef MWWorld::CellStore CellStore; + ///< \deprecated boost::any mPtr; ESM::CellRef *mCellRef; @@ -51,7 +46,7 @@ namespace MWWorld } template - Ptr (ESMS::LiveCellRef *liveCellRef, CellStore *cell) + Ptr (MWWorld::LiveCellRef *liveCellRef, CellStore *cell) : mContainerStore (0) { mPtr = liveCellRef; @@ -62,9 +57,9 @@ namespace MWWorld } template - ESMS::LiveCellRef *get() const + MWWorld::LiveCellRef *get() const { - return boost::any_cast*> (mPtr); + return boost::any_cast*> (mPtr); } ESM::CellRef& getCellRef() const; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index e1c14b907..14ddd3ec5 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -1,9 +1,10 @@ #include "refdata.hpp" -#include +#include #include "customdata.hpp" +#include "cellstore.hpp" namespace MWWorld { diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 30d676f13..3a6e0fc9f 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -1,14 +1,15 @@ #ifndef GAME_MWWORLD_REFDATA_H #define GAME_MWWORLD_REFDATA_H -#include - -#include - #include #include "../mwscript/locals.hpp" +namespace Ogre +{ + class SceneNode; +} + namespace ESM { class Script; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index a47137d25..eb03e9a7b 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -1,20 +1,15 @@ #include "scene.hpp" -#include "world.hpp" + +#include #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" /// FIXME +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/mechanicsmanager.hpp" - -#include "../mwsound/soundmanager.hpp" - -#include "../mwgui/window_manager.hpp" - -#include "../mwworld/world.hpp" /// FIXME -#include "../mwworld/manualref.hpp" /// FIXME - -#include "ptr.hpp" #include "player.hpp" -#include "class.hpp" +#include "localscripts.hpp" #include "cellfunctors.hpp" @@ -23,7 +18,7 @@ namespace template void insertCellRefList(MWRender::RenderingManager& rendering, - T& cellRefList, ESMS::CellStore &cell, MWWorld::PhysicsSystem& physics) + T& cellRefList, MWWorld::CellStore &cell, MWWorld::PhysicsSystem& physics) { if (!cellRefList.list.empty()) { @@ -86,7 +81,7 @@ namespace MWWorld if (!((*iter)->cell->data.flags & ESM::Cell::Interior)) { - ESM::Land* land = mWorld->getStore().lands.search((*iter)->cell->data.gridX,(*iter)->cell->data.gridY); + ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search((*iter)->cell->data.gridX,(*iter)->cell->data.gridY); if (land) mPhysics->removeHeightField( (*iter)->cell->data.gridX, (*iter)->cell->data.gridY ); } @@ -95,7 +90,7 @@ namespace MWWorld mRendering.removeCell(*iter); //mPhysics->removeObject("Unnamed_43"); - mWorld->getLocalScripts().clearCell (*iter); + MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); MWBase::Environment::get().getMechanicsManager()->dropActors (*iter); MWBase::Environment::get().getSoundManager()->stopSound (*iter); mActiveCells.erase(*iter); @@ -107,7 +102,7 @@ namespace MWWorld void Scene::loadCell (Ptr::CellStore *cell) { // register local scripts - mWorld->getLocalScripts().addCell (cell); + MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell); @@ -124,7 +119,7 @@ namespace MWWorld if (!(cell->cell->data.flags & ESM::Cell::Interior)) { - ESM::Land* land = mWorld->getStore().lands.search(cell->cell->data.gridX,cell->cell->data.gridY); + ESM::Land* land = MWBase::Environment::get().getWorld()->getStore().lands.search(cell->cell->data.gridX,cell->cell->data.gridY); if (land) mPhysics->addHeightField (land->landData->heights, cell->cell->data.gridX, cell->cell->data.gridY, @@ -139,23 +134,36 @@ namespace MWWorld } - void Scene::playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, + void + Scene::playerCellChange( + MWWorld::CellStore *cell, + const ESM::Position& pos, bool adjustPlayerPos) { bool hasWater = cell->cell->data.flags & cell->cell->HasWater; mPhysics->setCurrentWater(hasWater, cell->cell->water); - if (adjustPlayerPos) - { - mWorld->getPlayer().setPos (position.pos[0], position.pos[1], position.pos[2]); - mWorld->getPlayer().setRot (position.rot[0], position.rot[1], position.rot[2]); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + world->getPlayer().setCell(cell); + + MWWorld::Ptr player = world->getPlayer().getPlayer(); + + if (adjustPlayerPos) { + world->moveObject(player, pos.pos[0], pos.pos[1], pos.pos[2]); + + float x = Ogre::Radian(pos.rot[0]).valueDegrees(); + float y = Ogre::Radian(pos.rot[1]).valueDegrees(); + float z = Ogre::Radian(pos.rot[2]).valueDegrees(); + world->rotateObject(player, x, y, z); } - mWorld->getPlayer().setCell (cell); + MWBase::MechanicsManager *mechMgr = + MWBase::Environment::get().getMechanicsManager(); - MWBase::Environment::get().getMechanicsManager()->addActor (mWorld->getPlayer().getPlayer()); - MWBase::Environment::get().getMechanicsManager()->watchActor (mWorld->getPlayer().getPlayer()); + mechMgr->addActor(player); + mechMgr->watchActor(player); - MWBase::Environment::get().getWindowManager()->changeCell( mCurrentCell ); + MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); } void Scene::changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos) @@ -163,7 +171,7 @@ namespace MWWorld mRendering.preCellChange(mCurrentCell); // remove active - MWBase::Environment::get().getMechanicsManager()->removeActor (mWorld->getPlayer().getPlayer()); + MWBase::Environment::get().getMechanicsManager()->removeActor (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); CellStoreCollection::iterator active = mActiveCells.begin(); @@ -202,7 +210,7 @@ namespace MWWorld if (iter==mActiveCells.end()) { - Ptr::CellStore *cell = mWorld->getExterior(x, y); + CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y); loadCell (cell); } @@ -228,10 +236,10 @@ namespace MWWorld // adjust player - playerCellChange (mWorld->getExterior(X, Y), position, adjustPlayerPos); + playerCellChange (mCurrentCell, position, adjustPlayerPos); // Sky system - mWorld->adjustSky(); + MWBase::Environment::get().getWorld()->adjustSky(); mRendering.switchToExterior(); @@ -239,9 +247,8 @@ namespace MWWorld } //We need the ogre renderer and a scene node. - Scene::Scene (World *world, MWRender::RenderingManager& rendering, PhysicsSystem *physics) - : mCurrentCell (0), mCellChanged (false), mWorld(world), - mPhysics(physics), mRendering(rendering) + Scene::Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics) + : mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering) { } @@ -263,7 +270,7 @@ namespace MWWorld { std::cout << "Changing to interior\n"; - Ptr::CellStore *cell = mWorld->getInterior(cellName); + CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(cellName); // remove active CellStoreCollection::iterator active = mActiveCells.begin(); @@ -287,7 +294,7 @@ namespace MWWorld mRendering.configureFog(*cell); // Sky system - mWorld->adjustSky(); + MWBase::Environment::get().getWorld()->adjustSky(); mCellChanged = true; } @@ -297,7 +304,7 @@ namespace MWWorld int x = 0; int y = 0; - mWorld->positionToIndex (position.pos[0], position.pos[1], x, y); + MWBase::Environment::get().getWorld()->positionToIndex (position.pos[0], position.pos[1], x, y); changeCell (x, y, position, true); } @@ -312,7 +319,7 @@ namespace MWWorld mCellChanged = false; } - void Scene::insertCell(ESMS::CellStore &cell) + void Scene::insertCell (Ptr::CellStore &cell) { // Loop through all references in the cell insertCellRefList(mRendering, cell.activators, cell, *mPhysics); @@ -337,137 +344,10 @@ namespace MWWorld insertCellRefList(mRendering, cell.weapons, cell, *mPhysics); } - - /// \todo this whole code needs major clean up, and doesn't belong in this class. - void Scene::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell) - { - std::string type = ptr.getTypeName(); - - MWWorld::Ptr newPtr; - - // insert into the correct CellRefList - if (type == typeid(ESM::Potion).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->potions.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->potions.list.back(), cell); - } - else if (type == typeid(ESM::Apparatus).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->appas.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->appas.list.back(), cell); - } - else if (type == typeid(ESM::Armor).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->armors.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->armors.list.back(), cell); - } - else if (type == typeid(ESM::Book).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->books.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->books.list.back(), cell); - } - else if (type == typeid(ESM::Clothing).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->clothes.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->clothes.list.back(), cell); - } - else if (type == typeid(ESM::Ingredient).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->ingreds.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->ingreds.list.back(), cell); - } - else if (type == typeid(ESM::Light).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->lights.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->lights.list.back(), cell); - } - else if (type == typeid(ESM::Tool).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->lockpicks.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->lockpicks.list.back(), cell); - } - else if (type == typeid(ESM::Repair).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->repairs.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->repairs.list.back(), cell); - } - else if (type == typeid(ESM::Probe).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->probes.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->probes.list.back(), cell); - } - else if (type == typeid(ESM::Weapon).name()) - { - ESMS::LiveCellRef* ref = ptr.get(); - cell->weapons.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->weapons.list.back(), cell); - } - else if (type == typeid(ESM::Miscellaneous).name()) - { - - // if this is gold, we need to fetch the correct mesh depending on the amount of gold. - if (MWWorld::Class::get(ptr).getName(ptr) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) - { - int goldAmount = ptr.getRefData().getCount(); - - std::string base = "Gold_001"; - if (goldAmount >= 100) - base = "Gold_100"; - else if (goldAmount >= 25) - base = "Gold_025"; - else if (goldAmount >= 10) - base = "Gold_010"; - else if (goldAmount >= 5) - base = "Gold_005"; - - MWWorld::ManualRef newRef (MWBase::Environment::get().getWorld()->getStore(), base); - - ESMS::LiveCellRef* ref = newRef.getPtr().get(); - - cell->miscItems.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell); - - ESM::Position& p = newPtr.getRefData().getPosition(); - p.pos[0] = ptr.getRefData().getPosition().pos[0]; - p.pos[1] = ptr.getRefData().getPosition().pos[1]; - p.pos[2] = ptr.getRefData().getPosition().pos[2]; - } - else - { - ESMS::LiveCellRef* ref = ptr.get(); - - cell->miscItems.list.push_back( *ref ); - newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell); - } - } - else - throw std::runtime_error("Trying to insert object of unhandled type"); - - - - newPtr.getRefData().setCount(ptr.getRefData().getCount()); - ptr.getRefData().setCount(0); - newPtr.getRefData().enable(); - - mRendering.addObject(newPtr); - MWWorld::Class::get(newPtr).insertObject(newPtr, *mPhysics); - - } - void Scene::addObjectToScene (const Ptr& ptr) { - mRendering.addObject (ptr); - MWWorld::Class::get (ptr).insertObject (ptr, *mPhysics); + mRendering.addObject(ptr); + MWWorld::Class::get(ptr).insertObject(ptr, *mPhysics); } void Scene::removeObjectFromScene (const Ptr& ptr) @@ -477,4 +357,16 @@ namespace MWWorld mPhysics->removeObject (ptr.getRefData().getHandle()); mRendering.removeObject (ptr); } + + bool Scene::isCellActive(const CellStore &cell) + { + CellStoreCollection::iterator active = mActiveCells.begin(); + while (active != mActiveCells.end()) { + if (**active == cell) { + return true; + } + ++active; + } + return false; + } } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 906580ff4..59e13dafe 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -1,21 +1,9 @@ #ifndef GAME_MWWORLD_SCENE_H #define GAME_MWWORLD_SCENE_H -#include -#include - -#include - -#include - -#include - #include "../mwrender/renderingmanager.hpp" -#include "../mwrender/renderinginterface.hpp" #include "physicssystem.hpp" -#include "refdata.hpp" -#include "ptr.hpp" #include "globals.hpp" namespace Ogre @@ -47,43 +35,43 @@ namespace MWRender namespace MWWorld { class Player; + class CellStore; + class Ptr; class Scene { - public: - typedef std::set CellStoreCollection; + typedef std::set CellStoreCollection; private: //OEngine::Render::OgreRenderer& mRenderer; - Ptr::CellStore* mCurrentCell; // the cell, the player is in + CellStore* mCurrentCell; // the cell, the player is in CellStoreCollection mActiveCells; bool mCellChanged; - World *mWorld; PhysicsSystem *mPhysics; MWRender::RenderingManager& mRendering; - void playerCellChange (Ptr::CellStore *cell, const ESM::Position& position, + void playerCellChange (CellStore *cell, const ESM::Position& position, bool adjustPlayerPos = true); public: - Scene (World *world, MWRender::RenderingManager& rendering, PhysicsSystem *physics); + Scene (MWRender::RenderingManager& rendering, PhysicsSystem *physics); ~Scene(); void unloadCell (CellStoreCollection::iterator iter); - void loadCell (Ptr::CellStore *cell); + void loadCell (CellStore *cell); void changeCell (int X, int Y, const ESM::Position& position, bool adjustPlayerPos); ///< Move from exterior to interior or from interior cell to a different /// interior cell. - Ptr::CellStore* getCurrentCell (); + CellStore* getCurrentCell (); const CellStoreCollection& getActiveCells () const; @@ -98,11 +86,7 @@ namespace MWWorld void markCellAsUnchanged(); - void insertCell(ESMS::CellStore &cell); - - /// this method is only meant for dropping objects into the gameworld from a container - /// and thus only handles object types that can be placed in a container - void insertObject(MWWorld::Ptr object, Ptr::CellStore* cell); + void insertCell (Ptr::CellStore &cell); void update (float duration); @@ -111,6 +95,8 @@ namespace MWWorld void removeObjectFromScene (const Ptr& ptr); ///< Remove an object from the scene, but not from the world model. + + bool isCellActive(const CellStore &cell); }; } diff --git a/apps/openmw/mwworld/timestamp.cpp b/apps/openmw/mwworld/timestamp.cpp index e2f3d6c63..126d5490c 100644 --- a/apps/openmw/mwworld/timestamp.cpp +++ b/apps/openmw/mwworld/timestamp.cpp @@ -76,12 +76,12 @@ namespace MWWorld TimeStamp operator+ (const TimeStamp& stamp, double hours) { - return TimeStamp (stamp) + hours; + return TimeStamp (stamp) += hours; } TimeStamp operator+ (double hours, const TimeStamp& stamp) { - return TimeStamp (stamp) + hours; + return TimeStamp (stamp) += hours; } double operator- (const TimeStamp& left, const TimeStamp& right) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 3d6547d6a..0adf87dae 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -1,17 +1,19 @@ #include "weather.hpp" -#include "world.hpp" -#include "player.hpp" - -#include "../mwrender/renderingmanager.hpp" -#include "../mwsound/soundmanager.hpp" #include #include -#include #include +#include + #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwrender/renderingmanager.hpp" + +#include "player.hpp" using namespace Ogre; using namespace MWWorld; @@ -473,8 +475,7 @@ WeatherResult WeatherManager::transition(float factor) result.mSunDiscColor = lerp(current.mSunDiscColor, other.mSunDiscColor); result.mFogDepth = lerp(current.mFogDepth, other.mFogDepth); result.mWindSpeed = lerp(current.mWindSpeed, other.mWindSpeed); - //result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); - result.mCloudSpeed = current.mCloudSpeed; + result.mCloudSpeed = lerp(current.mCloudSpeed, other.mCloudSpeed); result.mCloudOpacity = lerp(current.mCloudOpacity, other.mCloudOpacity); result.mGlareView = lerp(current.mGlareView, other.mGlareView); result.mNightFade = lerp(current.mNightFade, other.mNightFade); @@ -686,13 +687,13 @@ void WeatherManager::update(float duration) mThunderFlash -= duration; if (mThunderFlash > 0) - mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); + mRendering->getSkyManager()->setLightningStrength( mThunderFlash / WeatherGlobals::mThunderThreshold ); else { srand(time(NULL)); mThunderChanceNeeded = rand() % 100; mThunderChance = 0; - mRendering->getSkyManager()->setThunder( 0.f ); + mRendering->getSkyManager()->setLightningStrength( 0.f ); } } else @@ -703,14 +704,14 @@ void WeatherManager::update(float duration) { mThunderFlash = WeatherGlobals::mThunderThreshold; - mRendering->getSkyManager()->setThunder( mThunderFlash / WeatherGlobals::mThunderThreshold ); + mRendering->getSkyManager()->setLightningStrength( mThunderFlash / WeatherGlobals::mThunderThreshold ); mThunderSoundDelay = WeatherGlobals::mThunderSoundDelay; } } } else - mRendering->getSkyManager()->setThunder(0.f); + mRendering->getSkyManager()->setLightningStrength(0.f); mRendering->setAmbientColour(result.mAmbientColor); mRendering->sunEnable(); @@ -722,7 +723,7 @@ void WeatherManager::update(float duration) { mRendering->sunDisable(); mRendering->skyDisable(); - mRendering->getSkyManager()->setThunder(0.f); + mRendering->getSkyManager()->setLightningStrength(0.f); } // play sounds diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp deleted file mode 100644 index e8391773b..000000000 --- a/apps/openmw/mwworld/world.hpp +++ /dev/null @@ -1,288 +0,0 @@ -#ifndef GAME_MWWORLD_WORLD_H -#define GAME_MWWORLD_WORLD_H - -#include -#include - -#include - -#include -#include - -#include "../mwrender/debugging.hpp" -#include "../mwrender/renderingmanager.hpp" - -#include "refdata.hpp" -#include "ptr.hpp" -#include "globals.hpp" -#include "scene.hpp" -#include "physicssystem.hpp" -#include "cells.hpp" -#include "localscripts.hpp" -#include "timestamp.hpp" - -#include -#include - -#include - -namespace Ogre -{ - class Vector3; -} - -namespace ESM -{ - struct Position; -} - -namespace Files -{ - class Collections; -} - -namespace Render -{ - class OgreRenderer; -} - -namespace MWRender -{ - class SkyManager; - class CellRender; -} - -namespace MWWorld -{ - class WeatherManager; - class Player; - - /// \brief The game world and its visual representation - - class World - { - public: - - enum RenderMode - { - Render_CollisionDebug, - Render_Wireframe, - Render_Pathgrid, - Render_Compositors - }; - - private: - - MWRender::RenderingManager* mRendering; - - MWWorld::WeatherManager* mWeatherManager; - - MWWorld::Scene *mWorldScene; - MWWorld::Player *mPlayer; - ESM::ESMReader mEsm; - ESMS::ESMStore mStore; - LocalScripts mLocalScripts; - MWWorld::Globals *mGlobalVariables; - MWWorld::PhysicsSystem *mPhysics; - bool mSky; - int mNextDynamicRecord; - - Cells mCells; - - OEngine::Physic::PhysicEngine* mPhysEngine; - - // not implemented - World (const World&); - World& operator= (const World&); - - Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cellStore); - - std::string mFacedHandle; - Ptr mFaced1; - Ptr mFaced2; - std::string mFaced1Name; - std::string mFaced2Name; - int mNumFacing; - std::map mFallback; - - unsigned long lastTick; - Ogre::Timer mTimer; - - int getDaysPerMonth (int month) const; - - bool moveObjectImp (Ptr ptr, float x, float y, float z); - ///< @return true if the active cell (cell player is in) changed - - public: - - World (OEngine::Render::OgreRenderer& renderer, - const Files::Collections& fileCollections, - const std::string& master, const boost::filesystem::path& resDir, bool newGame, - const std::string& encoding, std::map fallbackMap); - - ~World(); - - OEngine::Render::Fader* getFader(); - - Ptr::CellStore *getExterior (int x, int y); - - Ptr::CellStore *getInterior (const std::string& name); - - void setWaterHeight(const float height); - void toggleWater(); - - void adjustSky(); - - void setFallbackValues(std::map fallbackMap); - - std::string getFallback(std::string key); - - std::string getFallback(std::string key, std::string def); - - MWWorld::Player& getPlayer(); - - const ESMS::ESMStore& getStore() const; - - ESM::ESMReader& getEsmReader(); - - LocalScripts& getLocalScripts(); - - bool hasCellChanged() const; - ///< Has the player moved to a different cell, since the last frame? - - bool isCellExterior() const; - bool isCellQuasiExterior() const; - - Ogre::Vector2 getNorthVector(Ptr::CellStore* cell); - ///< get north vector (OGRE coordinates) for given interior cell - - Globals::Data& getGlobalVariable (const std::string& name); - - Globals::Data getGlobalVariable (const std::string& name) const; - - char getGlobalVariableType (const std::string& name) const; - ///< Return ' ', if there is no global variable with this name. - - Ptr getPtr (const std::string& name, bool activeOnly); - ///< Return a pointer to a liveCellRef with the given name. - /// \param activeOnly do non search inactive cells. - - Ptr getPtrViaHandle (const std::string& handle); - ///< Return a pointer to a liveCellRef with the given Ogre handle. - - /// \todo enable reference in the OGRE scene - void enable (Ptr reference); - - /// \todo 5disable reference in the OGRE scene - void disable (Ptr reference); - - void advanceTime (double hours); - ///< Advance in-game time. - - void setHour (double hour); - ///< Set in-game time hour. - - void setMonth (int month); - ///< Set in-game time month. - - void setDay (int day); - ///< Set in-game time day. - - TimeStamp getTimeStamp() const; - ///< Return current in-game time stamp. - - bool toggleSky(); - ///< \return Resulting mode - - void changeWeather(const std::string& region, const unsigned int id); - - int getCurrentWeather() const; - - int getMasserPhase() const; - - int getSecundaPhase() const; - - void setMoonColour (bool red); - - float getTimeScaleFactor() const; - - void changeToInteriorCell (const std::string& cellName, const ESM::Position& position); - ///< Move to interior cell. - - void changeToExteriorCell (const ESM::Position& position); - ///< Move to exterior cell. - - const ESM::Cell *getExterior (const std::string& cellName) const; - ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. - - void markCellAsUnchanged(); - - std::string getFacedHandle(); - ///< Return handle of the object the player is looking at - - void deleteObject (Ptr ptr); - - void moveObject (Ptr ptr, float x, float y, float z); - - void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; - ///< Convert cell numbers to position. - - void positionToIndex (float x, float y, int &cellX, int &cellY) const; - ///< Convert position to cell numbers - - void doPhysics (const std::vector >& actors, - float duration); - ///< Run physics simulation and modify \a world accordingly. - - bool toggleCollisionMode(); - ///< Toggle collision mode for player. If disabled player object should ignore - /// collisions and gravity. - ///< \return Resulting mode - - bool toggleRenderMode (RenderMode mode); - ///< Toggle a render mode. - ///< \return Resulting mode - - std::pair createRecord (const ESM::Potion& record); - ///< Create a new recrod (of type potion) in the ESM store. - /// \return ID, pointer to created record - - std::pair createRecord (const ESM::Class& record); - ///< Create a new recrod (of type class) in the ESM store. - /// \return ID, pointer to created record - - const ESM::Cell *createRecord (const ESM::Cell& record); - ///< Create a new recrod (of type cell) in the ESM store. - /// \return ID, pointer to created record - - void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, - int number = 1); - ///< Run animation for a MW-reference. Calls to this function for references that are - /// currently not in the rendered scene should be ignored. - /// - /// \param mode: 0 normal, 1 immediate start, 2 immediate loop - /// \param number How offen the animation should be run - - void skipAnimation (const MWWorld::Ptr& ptr); - ///< Skip the animation for the given MW-reference for one frame. Calls to this function for - /// references that are currently not in the rendered scene should be ignored. - - void update (float duration); - - bool placeObject(MWWorld::Ptr object, float cursorX, float cursorY); - ///< place an object into the gameworld at the specified cursor position - /// @param object - /// @param cursor X (relative 0-1) - /// @param cursor Y (relative 0-1) - /// @return true if the object was placed, or false if it was rejected because the position is too far away - - void dropObjectOnGround(MWWorld::Ptr object); - - bool canPlaceObject(float cursorX, float cursorY); - ///< @return true if it is possible to place on object at specified cursor location - - void processChangedSettings(const Settings::CategorySettingVector& settings); - }; -} - -#endif diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/worldimp.cpp similarity index 75% rename from apps/openmw/mwworld/world.cpp rename to apps/openmw/mwworld/worldimp.cpp index e8d555689..8ace54378 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1,42 +1,30 @@ -#include "world.hpp" - -#include -#include +#include "worldimp.hpp" #include #include #include "../mwbase/environment.hpp" +#include "../mwbase/soundmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" -#include "../mwmechanics/mechanicsmanager.hpp" - -#include "../mwsound/soundmanager.hpp" - -#include "../mwgui/window_manager.hpp" - -#include "ptr.hpp" -#include "class.hpp" #include "player.hpp" -#include "weather.hpp" #include "manualref.hpp" -#include "refdata.hpp" -#include "globals.hpp" #include "cellfunctors.hpp" -#include using namespace Ogre; namespace { template void listCellScripts (const ESMS::ESMStore& store, - ESMS::CellRefList& cellRefList, MWWorld::LocalScripts& localScripts, + MWWorld::CellRefList& cellRefList, MWWorld::LocalScripts& localScripts, MWWorld::Ptr::CellStore *cell) { - for (typename ESMS::CellRefList::List::iterator iter ( + for (typename MWWorld::CellRefList::List::iterator iter ( cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) { @@ -53,14 +41,14 @@ namespace } template - ESMS::LiveCellRef *searchViaHandle (const std::string& handle, - ESMS::CellRefList& refList) + MWWorld::LiveCellRef *searchViaHandle (const std::string& handle, + MWWorld::CellRefList& refList) { - typedef typename ESMS::CellRefList::List::iterator iterator; + typedef typename MWWorld::CellRefList::List::iterator iterator; for (iterator iter (refList.list.begin()); iter!=refList.list.end(); ++iter) { - if(iter->mData.getBaseNode()){ + if(iter->mData.getCount() > 0 && iter->mData.getBaseNode()){ if (iter->mData.getHandle()==handle) { return &*iter; @@ -75,45 +63,45 @@ namespace MWWorld { Ptr World::getPtrViaHandle (const std::string& handle, Ptr::CellStore& cell) { - if (ESMS::LiveCellRef *ref = + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.activators)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.potions)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.potions)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.appas)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.appas)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.armors)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.armors)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.books)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.books)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.clothes)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.clothes)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.containers)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.creatures)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.doors)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.doors)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.ingreds)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.lights)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.lights)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.lockpicks)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.lockpicks)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.miscItems)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.miscItems)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.npcs)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.npcs)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.probes)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.probes)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.repairs)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.repairs)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.statics)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.statics)) return Ptr (ref, &cell); - if (ESMS::LiveCellRef *ref = searchViaHandle (handle, cell.weapons)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.weapons)) return Ptr (ref, &cell); return Ptr(); } @@ -154,19 +142,19 @@ namespace MWWorld mRendering->skyDisable(); } - void World::setFallbackValues(std::map fallbackMap) + void World::setFallbackValues (const std::map& fallbackMap) { mFallback = fallbackMap; } - std::string World::getFallback(std::string key) + std::string World::getFallback (const std::string& key) const { return getFallback(key, ""); } - std::string World::getFallback(std::string key, std::string def) + std::string World::getFallback (const std::string& key, const std::string& def) const { - std::map::iterator it; + std::map::const_iterator it; if((it = mFallback.find(key)) == mFallback.end()) { return def; @@ -179,7 +167,7 @@ namespace MWWorld const std::string& master, const boost::filesystem::path& resDir, bool newGame, const std::string& encoding, std::map fallbackMap) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), - mSky (true), mNextDynamicRecord (0), mCells (mStore, mEsm, *this), + mSky (true), mNextDynamicRecord (0), mCells (mStore, mEsm), mNumFacing(0) { mPhysics = new PhysicsSystem(renderer); @@ -198,8 +186,9 @@ namespace MWWorld mEsm.open (masterPath.string()); mStore.load (mEsm); - MWRender::Player* play = &(mRendering->getPlayer()); - mPlayer = new MWWorld::Player (play, mStore.npcs.find ("player"), *this); + mPlayer = new MWWorld::Player (mStore.npcs.find ("player"), *this); + mRendering->attachCameraTo(mPlayer->getPlayer()); + mPhysics->addActor (mPlayer->getPlayer().getRefData().getHandle(), "", Ogre::Vector3 (0, 0, 0)); // global variables @@ -211,7 +200,7 @@ namespace MWWorld mGlobalVariables->setInt ("chargenstate", 1); } - mWorldScene = new Scene(this, *mRendering, mPhysics); + mWorldScene = new Scene(*mRendering, mPhysics); setFallbackValues(fallbackMap); @@ -351,7 +340,7 @@ namespace MWWorld throw std::runtime_error ("unknown Ogre handle: " + handle); } - void World::enable (Ptr reference) + void World::enable (const Ptr& reference) { if (!reference.getRefData().isEnabled()) { @@ -362,7 +351,7 @@ namespace MWWorld } } - void World::disable (Ptr reference) + void World::disable (const Ptr& reference) { if (reference.getRefData().isEnabled()) { @@ -537,7 +526,7 @@ namespace MWWorld } } - void World::deleteObject (Ptr ptr) + void World::deleteObject (const Ptr& ptr) { if (ptr.getRefData().getCount()>0) { @@ -552,49 +541,110 @@ namespace MWWorld } } - bool World::moveObjectImp (Ptr ptr, float x, float y, float z) + void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { - bool ret = false; - ptr.getRefData().getPosition().pos[0] = x; - ptr.getRefData().getPosition().pos[1] = y; - ptr.getRefData().getPosition().pos[2] = z; - if (ptr==mPlayer->getPlayer()) - { - //std::cout << "X:" << ptr.getRefData().getPosition().pos[0] << " Z: " << ptr.getRefData().getPosition().pos[1] << "\n"; + ESM::Position &pos = ptr.getRefData().getPosition(); + pos.pos[0] = x, pos.pos[1] = y, pos.pos[2] = z; + Ogre::Vector3 vec(x, y, z); - Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); - if (currentCell) - { - if (!(currentCell->cell->data.flags & ESM::Cell::Interior)) - { - // exterior -> adjust loaded cells - int cellX = 0; - int cellY = 0; - - positionToIndex (x, y, cellX, cellY); - - if (currentCell->cell->data.gridX!=cellX || currentCell->cell->data.gridY!=cellY) - { - mWorldScene->changeCell (cellX, cellY, mPlayer->getPlayer().getRefData().getPosition(), false); - ret = true; - } + CellStore *currCell = ptr.getCell(); + bool isPlayer = ptr == mPlayer->getPlayer(); + bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; + if (*currCell != newCell) { + if (isPlayer) { + if (!newCell.isExterior()) { + changeToInteriorCell(newCell.cell->name, pos); + } else { + int cellX = newCell.cell->data.gridX; + int cellY = newCell.cell->data.gridY; + mWorldScene->changeCell(cellX, cellY, pos, false); } + } else { + if (!mWorldScene->isCellActive(*currCell)) { + copyObjectToCell(ptr, newCell, pos); + } else if (!mWorldScene->isCellActive(newCell)) { + MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + mWorldScene->removeObjectFromScene(ptr); + mLocalScripts.remove(ptr); + haveToMove = false; + } else { + MWWorld::Ptr copy = + MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + + mRendering->moveObjectToCell(copy, vec, currCell); + + if (MWWorld::Class::get(ptr).isActor()) { + MWBase::MechanicsManager *mechMgr = + MWBase::Environment::get().getMechanicsManager(); + + mechMgr->removeActor(ptr); + mechMgr->addActor(copy); + } else { + std::string script = + MWWorld::Class::get(ptr).getScript(ptr); + if (!script.empty()) { + mLocalScripts.remove(ptr); + mLocalScripts.add(script, copy); + } + } + } + ptr.getRefData().setCount(0); } } - - /// \todo cell change for non-player ref - - mRendering->moveObject (ptr, Ogre::Vector3 (x, y, z)); - - return ret; + if (haveToMove) { + mRendering->moveObject(ptr, vec); + mPhysics->moveObject(ptr.getRefData().getHandle(), vec); + } } - void World::moveObject (Ptr ptr, float x, float y, float z) + bool World::moveObjectImp(const Ptr& ptr, float x, float y, float z) + { + CellStore *cell = ptr.getCell(); + if (cell->isExterior()) { + int cellX, cellY; + positionToIndex(x, y, cellX, cellY); + + cell = getExterior(cellX, cellY); + } + moveObject(ptr, *cell, x, y, z); + + return cell != ptr.getCell(); + } + + void World::moveObject (const Ptr& ptr, float x, float y, float z) { moveObjectImp(ptr, x, y, z); + } - mPhysics->moveObject (ptr.getRefData().getHandle(), Ogre::Vector3 (x, y, z)); + void World::scaleObject (const Ptr& ptr, float scale) + { + MWWorld::Class::get(ptr).adjustScale(ptr,scale); + + ptr.getCellRef().scale = scale; + //scale = scale/ptr.getRefData().getBaseNode()->getScale().x; + ptr.getRefData().getBaseNode()->setScale(scale,scale,scale); + mPhysics->scaleObject( ptr.getRefData().getHandle(), scale ); + } + + void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) + { + Ogre::Vector3 rot; + rot.x = Ogre::Degree(x).valueRadians(); + rot.y = Ogre::Degree(y).valueRadians(); + rot.z = Ogre::Degree(z).valueRadians(); + + if (mRendering->rotateObject(ptr, rot, adjust)) { + float *objRot = ptr.getRefData().getPosition().rot; + objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; + + if (ptr.getRefData().getBaseNode() != 0) { + mPhysics->rotateObject( + ptr.getRefData().getHandle(), + ptr.getRefData().getBaseNode()->getOrientation() + ); + } + } } void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const @@ -753,6 +803,8 @@ namespace MWWorld void World::update (float duration) { + /// \todo split this function up into subfunctions + mWorldScene->update (duration); mWeatherManager->update (duration); @@ -959,10 +1011,10 @@ namespace MWWorld return mRendering->getFader(); } - Ogre::Vector2 World::getNorthVector(Ptr::CellStore* cell) + Ogre::Vector2 World::getNorthVector (CellStore* cell) { - ESMS::CellRefList statics = cell->statics; - ESMS::LiveCellRef* ref = statics.find("northmarker"); + MWWorld::CellRefList statics = cell->statics; + MWWorld::LiveCellRef* ref = statics.find("northmarker"); if (!ref) return Vector2(0, 1); Ogre::SceneNode* node = ref->mData.getBaseNode(); @@ -981,14 +1033,14 @@ namespace MWWorld mRendering->toggleWater(); } - bool World::placeObject(MWWorld::Ptr object, float cursorX, float cursorY) + bool World::placeObject (const Ptr& object, float cursorX, float cursorY) { std::pair result = mPhysics->castRay(cursorX, cursorY); if (!result.first) return false; - MWWorld::Ptr::CellStore* cell; + CellStore* cell; if (isCellExterior()) { int cellX, cellY; @@ -998,14 +1050,13 @@ namespace MWWorld else cell = getPlayer().getPlayer().getCell(); - ESM::Position& pos = object.getRefData().getPosition(); + ESM::Position pos = getPlayer().getPlayer().getRefData().getPosition(); pos.pos[0] = result.second[0]; pos.pos[1] = -result.second[2]; pos.pos[2] = result.second[1]; - mWorldScene->insertObject(object, cell); - - /// \todo retrieve the bounds of the object and translate it accordingly + copyObjectToCell(object, *cell, pos); + object.getRefData().setCount(0); return true; } @@ -1021,22 +1072,84 @@ namespace MWWorld return true; } - void World::dropObjectOnGround(MWWorld::Ptr object) + void + World::copyObjectToCell(const Ptr &object, CellStore &cell, const ESM::Position &pos) + { + /// \todo add searching correct cell for position specified + MWWorld::Ptr dropped = + MWWorld::Class::get(object).copyToCell(object, cell, pos); + + Ogre::Vector3 min, max; + if (mPhysics->getObjectAABB(object, min, max)) { + float *pos = dropped.getRefData().getPosition().pos; + pos[0] -= (min.x + max.x) / 2; + pos[1] -= (min.y + max.y) / 2; + pos[2] -= min.z; + } + + if (mWorldScene->isCellActive(cell)) { + if (dropped.getRefData().isEnabled()) { + mWorldScene->addObjectToScene(dropped); + } + std::string script = MWWorld::Class::get(dropped).getScript(dropped); + if (!script.empty()) { + mLocalScripts.add(script, dropped); + } + } + } + + void World::dropObjectOnGround (const Ptr& object) { MWWorld::Ptr::CellStore* cell = getPlayer().getPlayer().getCell(); - float* playerPos = getPlayer().getPlayer().getRefData().getPosition().pos; + ESM::Position pos = + getPlayer().getPlayer().getRefData().getPosition(); - ESM::Position& pos = object.getRefData().getPosition(); - pos.pos[0] = playerPos[0]; - pos.pos[1] = playerPos[1]; - pos.pos[2] = playerPos[2]; + Ogre::Vector3 orig = + Ogre::Vector3(pos.pos[0], pos.pos[1], pos.pos[2]); + Ogre::Vector3 dir = Ogre::Vector3(0, 0, -1); - mWorldScene->insertObject(object, cell); + float len = (pos.pos[2] >= 0) ? pos.pos[2] : -pos.pos[2]; + len += 100.0; + + std::pair hit = + mPhysics->castRay(orig, dir, len); + pos.pos[2] = hit.second.z; + + copyObjectToCell(object, *cell, pos); + object.getRefData().setCount(0); } void World::processChangedSettings(const Settings::CategorySettingVector& settings) { mRendering->processChangedSettings(settings); } + + void World::getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) + { + mRendering->getTriangleBatchCount(triangles, batches); + } + + bool + World::isSwimming(const MWWorld::Ptr &object) + { + /// \todo add check ifActor() - only actors can swim + float *fpos = object.getRefData().getPosition().pos; + Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); + + /// \fixme should rely on object height + pos.z += 30; + + return isUnderwater(*object.getCell()->cell, pos); + } + + bool + World::isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos) + { + if (!(cell.data.flags & ESM::Cell::HasWater)) { + return false; + } + return pos.z < cell.water; + } + } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp new file mode 100644 index 000000000..4031a180a --- /dev/null +++ b/apps/openmw/mwworld/worldimp.hpp @@ -0,0 +1,283 @@ +#ifndef GAME_MWWORLD_WORLDIMP_H +#define GAME_MWWORLD_WORLDIMP_H + +#include + +#include "../mwrender/debugging.hpp" + +#include "ptr.hpp" +#include "scene.hpp" +#include "physicssystem.hpp" +#include "cells.hpp" +#include "localscripts.hpp" +#include "timestamp.hpp" + +#include "../mwbase/world.hpp" + +namespace Ogre +{ + class Vector3; +} + +namespace ESM +{ + struct Position; +} + +namespace Files +{ + class Collections; +} + +namespace Render +{ + class OgreRenderer; +} + +namespace MWRender +{ + class SkyManager; + class CellRender; +} + +namespace MWWorld +{ + class WeatherManager; + class Player; + + /// \brief The game world and its visual representation + + class World : public MWBase::World + { + MWRender::RenderingManager* mRendering; + + MWWorld::WeatherManager* mWeatherManager; + + MWWorld::Scene *mWorldScene; + MWWorld::Player *mPlayer; + ESM::ESMReader mEsm; + ESMS::ESMStore mStore; + LocalScripts mLocalScripts; + MWWorld::Globals *mGlobalVariables; + MWWorld::PhysicsSystem *mPhysics; + bool mSky; + int mNextDynamicRecord; + + Cells mCells; + + OEngine::Physic::PhysicEngine* mPhysEngine; + + // not implemented + World (const World&); + World& operator= (const World&); + + Ptr getPtrViaHandle (const std::string& handle, Ptr::CellStore& cellStore); + + std::string mFacedHandle; + Ptr mFaced1; + Ptr mFaced2; + std::string mFaced1Name; + std::string mFaced2Name; + int mNumFacing; + std::map mFallback; + + unsigned long lastTick; + Ogre::Timer mTimer; + + int getDaysPerMonth (int month) const; + + bool moveObjectImp (const Ptr& ptr, float x, float y, float z); + ///< @return true if the active cell (cell player is in) changed + + virtual void + copyObjectToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos); + + public: + + World (OEngine::Render::OgreRenderer& renderer, + const Files::Collections& fileCollections, + const std::string& master, const boost::filesystem::path& resDir, bool newGame, + const std::string& encoding, std::map fallbackMap); + + virtual ~World(); + + virtual OEngine::Render::Fader* getFader(); + ///< \ŧodo remove this function. Rendering details should not be exposed. + + virtual CellStore *getExterior (int x, int y); + + virtual CellStore *getInterior (const std::string& name); + + virtual void setWaterHeight(const float height); + + virtual void toggleWater(); + + virtual void adjustSky(); + + virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); + + virtual void setFallbackValues (const std::map& fallbackMap); + + virtual std::string getFallback (const std::string& key) const; + + virtual std::string getFallback (const std::string& key, const std::string& def) const; + + virtual Player& getPlayer(); + + virtual const ESMS::ESMStore& getStore() const; + + virtual ESM::ESMReader& getEsmReader(); + + virtual LocalScripts& getLocalScripts(); + + virtual bool hasCellChanged() const; + ///< Has the player moved to a different cell, since the last frame? + + virtual bool isCellExterior() const; + + virtual bool isCellQuasiExterior() const; + + virtual Ogre::Vector2 getNorthVector (CellStore* cell); + ///< get north vector (OGRE coordinates) for given interior cell + + virtual Globals::Data& getGlobalVariable (const std::string& name); + + virtual Globals::Data getGlobalVariable (const std::string& name) const; + + virtual char getGlobalVariableType (const std::string& name) const; + ///< Return ' ', if there is no global variable with this name. + + virtual Ptr getPtr (const std::string& name, bool activeOnly); + ///< Return a pointer to a liveCellRef with the given name. + /// \param activeOnly do non search inactive cells. + + virtual Ptr getPtrViaHandle (const std::string& handle); + ///< Return a pointer to a liveCellRef with the given Ogre handle. + + virtual void enable (const Ptr& ptr); + + virtual void disable (const Ptr& ptr); + + virtual void advanceTime (double hours); + ///< Advance in-game time. + + virtual void setHour (double hour); + ///< Set in-game time hour. + + virtual void setMonth (int month); + ///< Set in-game time month. + + virtual void setDay (int day); + ///< Set in-game time day. + + virtual TimeStamp getTimeStamp() const; + ///< Return current in-game time stamp. + + virtual bool toggleSky(); + ///< \return Resulting mode + + virtual void changeWeather (const std::string& region, unsigned int id); + + virtual int getCurrentWeather() const; + + virtual int getMasserPhase() const; + + virtual int getSecundaPhase() const; + + virtual void setMoonColour (bool red); + + virtual float getTimeScaleFactor() const; + + virtual void changeToInteriorCell (const std::string& cellName, + const ESM::Position& position); + ///< Move to interior cell. + + virtual void changeToExteriorCell (const ESM::Position& position); + ///< Move to exterior cell. + + virtual const ESM::Cell *getExterior (const std::string& cellName) const; + ///< Return a cell matching the given name or a 0-pointer, if there is no such cell. + + virtual void markCellAsUnchanged(); + + virtual std::string getFacedHandle(); + ///< Return handle of the object the player is looking at + + virtual void deleteObject (const Ptr& ptr); + + virtual void moveObject (const Ptr& ptr, float x, float y, float z); + virtual void moveObject (const Ptr& ptr, CellStore &newCell, float x, float y, float z); + + virtual void scaleObject (const Ptr& ptr, float scale); + + /// Rotates object, uses degrees + /// \param adjust indicates rotation should be set or adjusted + virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) + const; + ///< Convert cell numbers to position. + + virtual void positionToIndex (float x, float y, int &cellX, int &cellY) const; + ///< Convert position to cell numbers + + virtual void doPhysics (const std::vector >& actors, + float duration); + ///< Run physics simulation and modify \a world accordingly. + + virtual bool toggleCollisionMode(); + ///< Toggle collision mode for player. If disabled player object should ignore + /// collisions and gravity. + ///< \return Resulting mode + + virtual bool toggleRenderMode (RenderMode mode); + ///< Toggle a render mode. + ///< \return Resulting mode + + virtual std::pair createRecord (const ESM::Potion& record); + ///< Create a new recrod (of type potion) in the ESM store. + /// \return ID, pointer to created record + + virtual std::pair createRecord (const ESM::Class& record); + ///< Create a new recrod (of type class) in the ESM store. + /// \return ID, pointer to created record + + virtual const ESM::Cell *createRecord (const ESM::Cell& record); + ///< Create a new recrod (of type cell) in the ESM store. + /// \return ID, pointer to created record + + virtual void playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, + int mode, int number = 1); + ///< Run animation for a MW-reference. Calls to this function for references that are + /// currently not in the rendered scene should be ignored. + /// + /// \param mode: 0 normal, 1 immediate start, 2 immediate loop + /// \param number How offen the animation should be run + + virtual void skipAnimation (const MWWorld::Ptr& ptr); + ///< Skip the animation for the given MW-reference for one frame. Calls to this function for + /// references that are currently not in the rendered scene should be ignored. + + virtual void update (float duration); + + virtual bool placeObject (const Ptr& object, float cursorX, float cursorY); + ///< place an object into the gameworld at the specified cursor position + /// @param object + /// @param cursor X (relative 0-1) + /// @param cursor Y (relative 0-1) + /// @return true if the object was placed, or false if it was rejected because the position is too far away + + virtual void dropObjectOnGround (const Ptr& object); + + virtual bool canPlaceObject(float cursorX, float cursorY); + ///< @return true if it is possible to place on object at specified cursor location + + virtual void processChangedSettings(const Settings::CategorySettingVector& settings); + + virtual bool isSwimming(const MWWorld::Ptr &object); + virtual bool isUnderwater(const ESM::Cell &cell, const Ogre::Vector3 &pos); + + }; +} + +#endif diff --git a/cmake/FindMyGUI.cmake b/cmake/FindMyGUI.cmake index 7278fe200..e2fefac7d 100644 --- a/cmake/FindMyGUI.cmake +++ b/cmake/FindMyGUI.cmake @@ -128,9 +128,11 @@ ELSE (WIN32) #Unix ENDIF (WIN32) #Do some preparation -SEPARATE_ARGUMENTS(MYGUI_INCLUDE_DIRS) -SEPARATE_ARGUMENTS(MYGUI_LIBRARIES) -SEPARATE_ARGUMENTS(MYGUI_PLATFORM_LIBRARIES) +IF (NOT WIN32) # This does not work on Windows for paths with spaces in them + SEPARATE_ARGUMENTS(MYGUI_INCLUDE_DIRS) + SEPARATE_ARGUMENTS(MYGUI_LIBRARIES) + SEPARATE_ARGUMENTS(MYGUI_PLATFORM_LIBRARIES) +ENDIF (NOT WIN32) SET(MYGUI_LIBRARIES ${MYGUI_LIBRARIES} ${FREETYPE_LIBRARIES}) diff --git a/cmake/OpenMWMacros.cmake b/cmake/OpenMWMacros.cmake index 024338d3a..e6f45fdb1 100644 --- a/cmake/OpenMWMacros.cmake +++ b/cmake/OpenMWMacros.cmake @@ -22,3 +22,10 @@ endforeach (f) endforeach (u) source_group ("components\\${dir}" FILES ${files}) endmacro (add_component_dir) + +macro (copy_all_files source_dir destination_dir files) +foreach (f ${files}) +get_filename_component(filename ${f} NAME) +configure_file(${source_dir}/${f} ${destination_dir}/${filename} COPYONLY) +endforeach (f) +endmacro (copy_all_files) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 8a1875d0f..c0585d5ee 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -35,7 +35,7 @@ add_component_dir (file_finder ) add_component_dir (esm_store - cell_store reclists store + reclists store ) add_component_dir (esm @@ -52,7 +52,7 @@ add_component_dir (misc add_component_dir (files linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager - filelibrary + filelibrary ogreplugin ) add_component_dir (compiler @@ -72,6 +72,11 @@ add_library(components STATIC ${COMPONENT_FILES}) target_link_libraries(components ${Boost_LIBRARIES} ${OGRE_LIBRARIES}) +# Fix for not visible pthreads functions for linker with glibc 2.15 +if (UNIX AND NOT APPLE) +target_link_libraries(components ${CMAKE_THREAD_LIBS_INIT}) +endif() + + # Make the variable accessible for other subdirectories set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE) - diff --git a/components/bsa/bsa_archive.cpp b/components/bsa/bsa_archive.cpp index d3b75d4ae..081207b0c 100644 --- a/components/bsa/bsa_archive.cpp +++ b/components/bsa/bsa_archive.cpp @@ -28,13 +28,11 @@ #include #include #include "bsa_file.hpp" -#include namespace { using namespace Ogre; -using namespace Mangle::Stream; using namespace Bsa; struct ciLessBoost : std::binary_function @@ -64,26 +62,13 @@ static bool fsstrict = false; /// An OGRE Archive wrapping a BSAFile archive class DirArchive: public Ogre::FileSystemArchive { - boost::filesystem::path currentdir; std::map, ciLessBoost> m; unsigned int cutoff; bool findFile(const String& filename, std::string& copy) const { - { - String passed = filename; - if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<' - || filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':' - || filename.at(filename.length() - 1) == '|') - { - passed = filename.substr(0, filename.length() - 2); - } - if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') - passed = filename.substr(0, filename.length() - 6); - copy = passed; - } - + copy = filename; std::replace(copy.begin(), copy.end(), '\\', '/'); if(copy.at(0) == '/') @@ -223,42 +208,20 @@ public: // OGRE's fault. You should NOT expect an open() command not to // have any side effects on the archive, and hence this function // should not have been declared const in the first place. - BSAFile *narc = (BSAFile*)&arc; + BSAFile *narc = const_cast(&arc); - String passed = filename; - if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<' - || filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':' - || filename.at(filename.length() - 1) == '|') - { - passed = filename.substr(0, filename.length() - 2); - } - if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') - passed = filename.substr(0, filename.length() - 6); // Open the file - StreamPtr strm = narc->getFile(passed.c_str()); - - // Wrap it into an Ogre::DataStream. - return DataStreamPtr(new Mangle2OgreStream(strm)); + return narc->getFile(filename.c_str()); } -bool exists(const String& filename) { - return cexists(filename); -} + bool exists(const String& filename) { + return arc.exists(filename.c_str()); + } - // Check if the file exists. bool cexists(const String& filename) const { - String passed = filename; - if(filename.at(filename.length() - 1) == '*' || filename.at(filename.length() - 1) == '?' || filename.at(filename.length() - 1) == '<' - || filename.at(filename.length() - 1) == '"' || filename.at(filename.length() - 1) == '>' || filename.at(filename.length() - 1) == ':' - || filename.at(filename.length() - 1) == '|') - { - passed = filename.substr(0, filename.length() - 2); - } - if(filename.at(filename.length() - 2) == '>' || filename.at(filename.length() - 2) == ':') - passed = filename.substr(0, filename.length() - 6); + return arc.exists(filename.c_str()); + } -return arc.exists(passed.c_str()); -} time_t getModifiedTime(const String&) { return 0; } // This is never called as far as I can see. diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index f19606703..1700e1aab 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -23,171 +23,235 @@ #include "bsa_file.hpp" -#include -#include - #include -#include -#include +#include +#include + +#include using namespace std; -using namespace Mangle::Stream; using namespace Bsa; +class ConstrainedDataStream : public Ogre::DataStream { + std::ifstream mStream; + const size_t mStart; + size_t mPos; + bool mIsEOF; + +public: + ConstrainedDataStream(const Ogre::String &fname, size_t start, size_t length) + : mStream(fname.c_str(), std::ios_base::binary), mStart(start), mPos(0), mIsEOF(false) + { + mSize = length; + if(!mStream.seekg(mStart, std::ios_base::beg)) + throw std::runtime_error("Error seeking to start of BSA entry"); + } + + ConstrainedDataStream(const Ogre::String &name, const Ogre::String &fname, + size_t start, size_t length) + : Ogre::DataStream(name), mStream(fname.c_str(), std::ios_base::binary), + mStart(start), mPos(0), mIsEOF(false) + { + mSize = length; + if(!mStream.seekg(mStart, std::ios_base::beg)) + throw std::runtime_error("Error seeking to start of BSA entry"); + } + + + virtual size_t read(void *buf, size_t count) + { + mStream.clear(); + + if(count > mSize-mPos) + { + count = mSize-mPos; + mIsEOF = true; + } + mStream.read(reinterpret_cast(buf), count); + + count = mStream.gcount(); + mPos += count; + return count; + } + + virtual void skip(long count) + { + if((count >= 0 && (size_t)count <= mSize-mPos) || + (count < 0 && (size_t)-count <= mPos)) + { + mStream.clear(); + if(mStream.seekg(count, std::ios_base::cur)) + { + mPos += count; + mIsEOF = false; + } + } + } + + virtual void seek(size_t pos) + { + if(pos < mSize) + { + mStream.clear(); + if(mStream.seekg(pos+mStart, std::ios_base::beg)) + { + mPos = pos; + mIsEOF = false; + } + } + } + + virtual size_t tell() const + { return mPos; } + + virtual bool eof() const + { return mIsEOF; } + + virtual void close() + { mStream.close(); } +}; + + /// Error handling void BSAFile::fail(const string &msg) { - throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + filename); + throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + filename); } /// Read header information from the input source void BSAFile::readHeader() { - /* - * The layout of a BSA archive is as follows: - * - * - 12 bytes header, contains 3 ints: - * id number - equal to 0x100 - * dirsize - size of the directory block (see below) - * numfiles - number of files - * - * ---------- start of directory block ----------- - * - * - 8 bytes*numfiles, each record contains: - * fileSize - * offset into data buffer (see below) - * - * - 4 bytes*numfiles, each record is an offset into the following name buffer - * - * - name buffer, indexed by the previous table, each string is - * null-terminated. Size is (dirsize - 12*numfiles). - * - * ---------- end of directory block ------------- - * - * - 8*filenum - hash table block, we currently ignore this - * - * ----------- start of data buffer -------------- - * - * - The rest of the archive is file data, indexed by the - * offsets in the directory block. The offsets start at 0 at - * the beginning of this buffer. - * - */ - assert(!isLoaded); - assert(input); - assert(input->hasSize); - assert(input->hasPosition); - assert(input->isSeekable); + /* + * The layout of a BSA archive is as follows: + * + * - 12 bytes header, contains 3 ints: + * id number - equal to 0x100 + * dirsize - size of the directory block (see below) + * numfiles - number of files + * + * ---------- start of directory block ----------- + * + * - 8 bytes*numfiles, each record contains: + * fileSize + * offset into data buffer (see below) + * + * - 4 bytes*numfiles, each record is an offset into the following name buffer + * + * - name buffer, indexed by the previous table, each string is + * null-terminated. Size is (dirsize - 12*numfiles). + * + * ---------- end of directory block ------------- + * + * - 8*filenum - hash table block, we currently ignore this + * + * ----------- start of data buffer -------------- + * + * - The rest of the archive is file data, indexed by the + * offsets in the directory block. The offsets start at 0 at + * the beginning of this buffer. + * + */ + assert(!isLoaded); - // Total archive size - size_t fsize = input->size(); + std::ifstream input(filename.c_str(), std::ios_base::binary); - if( fsize < 12 ) - fail("File too small to be a valid BSA archive"); - - // Get essential header numbers - size_t dirsize, filenum; - - { - // First 12 bytes - uint32_t head[3]; - - input->read(head, 12); - - if(head[0] != 0x100) - fail("Unrecognized BSA header"); - - // Total number of bytes used in size/offset-table + filename - // sections. - dirsize = head[1]; - - // Number of files - filenum = head[2]; - } - - // Each file must take up at least 21 bytes of data in the bsa. So - // if files*21 overflows the file size then we are guaranteed that - // the archive is corrupt. - if( (filenum*21 > fsize -12) || - (dirsize+8*filenum > fsize -12) ) - fail("Directory information larger than entire archive"); - - // Read the offset info into a temporary buffer - vector offsets(3*filenum); - input->read(&offsets[0], 12*filenum); - - // Read the string table - stringBuf.resize(dirsize-12*filenum); - input->read(&stringBuf[0], stringBuf.size()); - - // Check our position - assert(input->tell() == 12+dirsize); - - // Calculate the offset of the data buffer. All file offsets are - // relative to this. 12 header bytes + directory + hash table - // (skipped) - size_t fileDataOffset = 12 + dirsize + 8*filenum; - - // Set up the the FileStruct table - files.resize(filenum); - for(size_t i=0;i fsize) - fail("Archive contains offsets outside itself"); - - // Add the file name to the lookup - lookup[fs.name] = i; + fsize = input.tellg(); + input.seekg(0); } - isLoaded = true; + if(fsize < 12) + fail("File too small to be a valid BSA archive"); + + // Get essential header numbers + size_t dirsize, filenum; + { + // First 12 bytes + uint32_t head[3]; + + input.read(reinterpret_cast(head), 12); + + if(head[0] != 0x100) + fail("Unrecognized BSA header"); + + // Total number of bytes used in size/offset-table + filename + // sections. + dirsize = head[1]; + + // Number of files + filenum = head[2]; + } + + // Each file must take up at least 21 bytes of data in the bsa. So + // if files*21 overflows the file size then we are guaranteed that + // the archive is corrupt. + if((filenum*21 > fsize -12) || (dirsize+8*filenum > fsize -12) ) + fail("Directory information larger than entire archive"); + + // Read the offset info into a temporary buffer + vector offsets(3*filenum); + input.read(reinterpret_cast(&offsets[0]), 12*filenum); + + // Read the string table + stringBuf.resize(dirsize-12*filenum); + input.read(&stringBuf[0], stringBuf.size()); + + // Check our position + assert(input.tellg() == std::streampos(12+dirsize)); + + // Calculate the offset of the data buffer. All file offsets are + // relative to this. 12 header bytes + directory + hash table + // (skipped) + size_t fileDataOffset = 12 + dirsize + 8*filenum; + + // Set up the the FileStruct table + files.resize(filenum); + for(size_t i=0;i fsize) + fail("Archive contains offsets outside itself"); + + // Add the file name to the lookup + lookup[fs.name] = i; + } + + isLoaded = true; } /// Get the index of a given file name, or -1 if not found int BSAFile::getIndex(const char *str) const { - Lookup::const_iterator it; - it = lookup.find(str); + Lookup::const_iterator it = lookup.find(str); + if(it == lookup.end()) + return -1; - if(it == lookup.end()) return -1; - else - { - int res = it->second; - assert(res >= 0 && res < static_cast (files.size())); - return res; - } + int res = it->second; + assert(res >= 0 && (size_t)res < files.size()); + return res; } /// Open an archive file. void BSAFile::open(const string &file) { - filename = file; - input = StreamPtr(new FileStream(file)); - readHeader(); + filename = file; + readHeader(); } -/** Open an archive from a generic stream. The 'name' parameter is - used for error messages. -*/ -void BSAFile::open(StreamPtr inp, const string &name) +Ogre::DataStreamPtr BSAFile::getFile(const char *file) { - filename = name; - input = inp; - readHeader(); -} - -StreamPtr BSAFile::getFile(const char *file) -{ - assert(file); - int i = getIndex(file); - if(i == -1) - fail("File not found: " + string(file)); - - FileStruct &fs = files[i]; - - return StreamPtr(new SliceStream(input, fs.offset, fs.fileSize)); + assert(file); + int i = getIndex(file); + if(i == -1) + fail("File not found: " + string(file)); + + const FileStruct &fs = files[i]; + return Ogre::DataStreamPtr(new ConstrainedDataStream(filename, fs.offset, fs.fileSize)); } diff --git a/components/bsa/bsa_file.hpp b/components/bsa/bsa_file.hpp index 95fac0f4d..6f3ab3bce 100644 --- a/components/bsa/bsa_file.hpp +++ b/components/bsa/bsa_file.hpp @@ -24,13 +24,15 @@ #ifndef BSA_BSA_FILE_H #define BSA_BSA_FILE_H -#include #include #include #include #include #include +#include + + namespace Bsa { @@ -39,98 +41,85 @@ namespace Bsa */ class BSAFile { - public: +public: + /// Represents one file entry in the archive + struct FileStruct + { + // File size and offset in file. We store the offset from the + // beginning of the file, not the offset into the data buffer + // (which is what is stored in the archive.) + uint32_t fileSize, offset; - /// Represents one file entry in the archive - struct FileStruct - { - // File size and offset in file. We store the offset from the - // beginning of the file, not the offset into the data buffer - // (which is what is stored in the archive.) - uint32_t fileSize, offset; + // Zero-terminated file name + const char *name; + }; + typedef std::vector FileList; - // Zero-terminated file name - char* name; - }; +private: + /// Table of files in this archive + FileList files; - typedef std::vector FileList; + /// Filename string buffer + std::vector stringBuf; - private: + /// True when an archive has been loaded + bool isLoaded; - /// The archive source - Mangle::Stream::StreamPtr input; + /// Used for error messages + std::string filename; - /// Table of files in this archive - FileList files; + /// Case insensitive string comparison + struct iltstr + { + bool operator()(const char *s1, const char *s2) const + { return strcasecmp(s1,s2) < 0; } + }; - /// Filename string buffer - std::vector stringBuf; + /** A map used for fast file name lookup. The value is the index into + the files[] vector above. The iltstr ensures that file name + checks are case insensitive. + */ + typedef std::map Lookup; + Lookup lookup; - /// True when an archive has been loaded - bool isLoaded; + /// Error handling + void fail(const std::string &msg); - /// Used for error messages - std::string filename; + /// Read header information from the input source + void readHeader(); - /// Case insensitive string comparison - struct iltstr - { - bool operator()(const char *s1, const char *s2) const - { return strcasecmp(s1,s2) < 0; } - }; + /// Get the index of a given file name, or -1 if not found + int getIndex(const char *str) const; - /** A map used for fast file name lookup. The value is the index into - the files[] vector above. The iltstr ensures that file name - checks are case insensitive. - */ - typedef std::map Lookup; - Lookup lookup; +public: + /* ----------------------------------- + * BSA management methods + * ----------------------------------- + */ - /// Error handling - void fail(const std::string &msg); + BSAFile() + : isLoaded(false) + { } - /// Read header information from the input source - void readHeader(); + /// Open an archive file. + void open(const std::string &file); - /// Get the index of a given file name, or -1 if not found - int getIndex(const char *str) const; + /* ----------------------------------- + * Archive file routines + * ----------------------------------- + */ - public: + /// Check if a file exists + bool exists(const char *file) const + { return getIndex(file) != -1; } - /* ----------------------------------- - * BSA management methods - * ----------------------------------- - */ + /** Open a file contained in the archive. Throws an exception if the + file doesn't exist. + */ + Ogre::DataStreamPtr getFile(const char *file); - BSAFile() - : input(), isLoaded(false) {} - - /// Open an archive file. - void open(const std::string &file); - - /** Open an archive from a generic stream. The 'name' parameter is - used for error messages. - */ - void open(Mangle::Stream::StreamPtr inp, const std::string &name); - - /* ----------------------------------- - * Archive file routines - * ----------------------------------- - */ - - /// Check if a file exists - bool exists(const char *file) const { return getIndex(file) != -1; } - - /** Open a file contained in the archive. Throws an exception if the - file doesn't exist. - - NOTE: All files opened from one archive will share a common file - handle. This is NOT thread safe. - */ - Mangle::Stream::StreamPtr getFile(const char *file); - - /// Get a list of all files - const FileList &getList() const + /// Get a list of all files + const FileList &getList() const { return files; } }; diff --git a/components/bsa/tests/bsatool_cmd.c b/components/bsa/tests/bsatool_cmd.c index f6e10d793..caa8cd720 100644 --- a/components/bsa/tests/bsatool_cmd.c +++ b/components/bsa/tests/bsatool_cmd.c @@ -13,8 +13,8 @@ #include "config.h" #endif -#include -#include +#include +#include #include #ifndef FIX_UNUSED diff --git a/components/bsa/tests/bsatool_cmd.h b/components/bsa/tests/bsatool_cmd.h index 65ebc3e96..98fe2633f 100644 --- a/components/bsa/tests/bsatool_cmd.h +++ b/components/bsa/tests/bsatool_cmd.h @@ -13,7 +13,7 @@ #include "config.h" #endif -#include /* for FILE */ +#include /* for FILE */ #ifdef __cplusplus extern "C" { diff --git a/components/compiler/streamerrorhandler.cpp b/components/compiler/streamerrorhandler.cpp index a1d12b708..8a74ad086 100644 --- a/components/compiler/streamerrorhandler.cpp +++ b/components/compiler/streamerrorhandler.cpp @@ -35,4 +35,5 @@ namespace Compiler << " " << message << std::endl; } - StreamErrorHandler::StreamErrorHandler (std::ostream& ErrorStream) : mStream (ErrorStream) {}} + StreamErrorHandler::StreamErrorHandler (std::ostream& ErrorStream) : mStream (ErrorStream) {} +} diff --git a/components/esm/esm_reader.cpp b/components/esm/esm_reader.cpp index e9bfcf5ee..95ef46e81 100644 --- a/components/esm/esm_reader.cpp +++ b/components/esm/esm_reader.cpp @@ -1,4 +1,5 @@ #include "esm_reader.hpp" +#include namespace ESM { @@ -27,7 +28,7 @@ void ESMReader::restoreContext(const ESM_Context &rc) void ESMReader::close() { - mEsm.reset(); + mEsm.setNull(); mCtx.filename.clear(); mCtx.leftFile = 0; mCtx.leftRec = 0; @@ -37,7 +38,7 @@ void ESMReader::close() mCtx.subName.val = 0; } -void ESMReader::openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name) +void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) { close(); mEsm = _esm; @@ -57,7 +58,7 @@ void ESMReader::openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name) mSpf = SF_Other; } -void ESMReader::open(Mangle::Stream::StreamPtr _esm, const std::string &name) +void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) { openRaw(_esm, name); @@ -107,14 +108,16 @@ void ESMReader::open(Mangle::Stream::StreamPtr _esm, const std::string &name) void ESMReader::open(const std::string &file) { - using namespace Mangle::Stream; - open(StreamPtr(new FileStream(file)), file); + std::ifstream *stream = OGRE_NEW_T(std::ifstream, Ogre::MEMCATEGORY_GENERAL)(file.c_str(), std::ios_base::binary); + // Ogre will delete the stream for us + open(Ogre::DataStreamPtr(new Ogre::FileStreamDataStream(stream)), file); } void ESMReader::openRaw(const std::string &file) { - using namespace Mangle::Stream; - openRaw(StreamPtr(new FileStream(file)), file); + std::ifstream *stream = OGRE_NEW_T(std::ifstream, Ogre::MEMCATEGORY_GENERAL)(file.c_str(), std::ios_base::binary); + // Ogre will delete the stream for us + openRaw(Ogre::DataStreamPtr(new Ogre::FileStreamDataStream(stream)), file); } int64_t ESMReader::getHNLong(const char *name) @@ -339,7 +342,7 @@ void ESMReader::fail(const std::string &msg) ss << "\n File: " << mCtx.filename; ss << "\n Record: " << mCtx.recName.toString(); ss << "\n Subrecord: " << mCtx.subName.toString(); - if (mEsm != NULL) + if (!mEsm.isNull()) ss << "\n Offset: 0x" << hex << mEsm->tell(); throw std::runtime_error(ss.str()); } diff --git a/components/esm/esm_reader.hpp b/components/esm/esm_reader.hpp index 340482891..13f1f4a01 100644 --- a/components/esm/esm_reader.hpp +++ b/components/esm/esm_reader.hpp @@ -1,18 +1,14 @@ #ifndef _ESM_READER_H #define _ESM_READER_H -#include - -#include #include #include -#include +#include #include #include -#include -#include -#include +#include + #include #include @@ -183,11 +179,11 @@ public: /// Raw opening. Opens the file and sets everything up but doesn't /// parse the header. - void openRaw(Mangle::Stream::StreamPtr _esm, const std::string &name); + void openRaw(Ogre::DataStreamPtr _esm, const std::string &name); /// Load ES file from a new stream, parses the header. Closes the /// currently open file first, if any. - void open(Mangle::Stream::StreamPtr _esm, const std::string &name); + void open(Ogre::DataStreamPtr _esm, const std::string &name); void open(const std::string &file); @@ -354,7 +350,7 @@ public: void setEncoding(const std::string& encoding); private: - Mangle::Stream::StreamPtr mEsm; + Ogre::DataStreamPtr mEsm; ESM_Context mCtx; diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp index d3bc36a77..cd36887b0 100644 --- a/components/esm/loadalch.cpp +++ b/components/esm/loadalch.cpp @@ -2,8 +2,10 @@ namespace ESM { -void Potion::load(ESMReader &esm) +void Potion::load(ESMReader &esm, const std::string& id) { + mId = id; + model = esm.getHNString("MODL"); icon = esm.getHNOString("TEXT"); // not ITEX here for some reason script = esm.getHNOString("SCRI"); diff --git a/components/esm/loadalch.hpp b/components/esm/loadalch.hpp index c21e5dea0..6917fb448 100644 --- a/components/esm/loadalch.hpp +++ b/components/esm/loadalch.hpp @@ -24,7 +24,9 @@ struct Potion std::string name, model, icon, script; EffectList effects; - void load(ESMReader &esm); + std::string mId; + + void load(ESMReader &esm, const std::string& id); }; } #endif diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp index 471f71780..a745ff669 100644 --- a/components/esm/loadingr.cpp +++ b/components/esm/loadingr.cpp @@ -3,8 +3,10 @@ namespace ESM { -void Ingredient::load(ESMReader &esm) +void Ingredient::load(ESMReader &esm, const std::string& id) { + mId = id; + model = esm.getHNString("MODL"); name = esm.getHNString("FNAM"); esm.getHNT(data, "IRDT", 56); diff --git a/components/esm/loadingr.hpp b/components/esm/loadingr.hpp index af9599ed0..5c1c3bd75 100644 --- a/components/esm/loadingr.hpp +++ b/components/esm/loadingr.hpp @@ -24,7 +24,9 @@ struct Ingredient IRDTstruct data; std::string name, model, icon, script; - void load(ESMReader &esm); + std::string mId; + + void load(ESMReader &esm, const std::string& id); }; } #endif diff --git a/components/esm_store/cell_store.hpp b/components/esm_store/cell_store.hpp deleted file mode 100644 index 024412291..000000000 --- a/components/esm_store/cell_store.hpp +++ /dev/null @@ -1,287 +0,0 @@ -#ifndef _GAME_CELL_STORE_H -#define _GAME_CELL_STORE_H - -/* - Cell storage. - - Used to load, look up and store all references in a single cell. - - Depends on esm/loadcell.hpp (loading from ESM) and esm_store.hpp - (looking up references.) Neither of these modules depend on us. - */ - -#include "store.hpp" -#include "components/esm/records.hpp" - -#include -#include -#include -#include -#include -#include - -namespace ESMS -{ - using namespace ESM; - - /// A reference to one object (of any type) in a cell. - /// - /// Constructing this with a CellRef instance in the constructor means that - /// in practice (where D is RefData) the possibly mutable data is copied - /// across to mData. If later adding data (such as position) to CellRef - /// this would have to be manually copied across. - template - struct LiveCellRef - { - LiveCellRef(const CellRef& cref, const X* b = NULL) : base(b), ref(cref), - mData(ref) {} - - - LiveCellRef(const X* b = NULL) : base(b), mData(ref) {} - - // The object that this instance is based on. - const X* base; - - /* Information about this instance, such as 3D location and - rotation and individual type-dependent data. - */ - CellRef ref; - - /// runtime-data - D mData; - }; - - /// A list of cell references - template - struct CellRefList - { - typedef LiveCellRef LiveRef; - typedef std::list List; - List list; - - // Search for the given reference in the given reclist from - // ESMStore. Insert the reference into the list if a match is - // found. If not, throw an exception. - template - void find(CellRef &ref, const Y& recList) - { - const X* obj = recList.find(ref.refID); - if(obj == NULL) - throw std::runtime_error("Error resolving cell reference " + ref.refID); - - list.push_back(LiveRef(ref, obj)); - } - - LiveRef *find (const std::string& name) - { - for (typename std::list::iterator iter (list.begin()); iter!=list.end(); ++iter) - { - if (iter->ref.refID==name) - return &*iter; - } - - return 0; - } - }; - - /// A storage struct for one single cell reference. - template - class CellStore - { - public: - - enum State - { - State_Unloaded, State_Preloaded, State_Loaded - }; - - CellStore (const ESM::Cell *cell_) : cell (cell_), mState (State_Unloaded) - { - mWaterLevel = cell->water; - } - - const ESM::Cell *cell; - State mState; - std::vector mIds; - - float mWaterLevel; - - // Lists for each individual object type - CellRefList activators; - CellRefList potions; - CellRefList appas; - CellRefList armors; - CellRefList books; - CellRefList clothes; - CellRefList containers; - CellRefList creatures; - CellRefList doors; - CellRefList ingreds; - CellRefList creatureLists; - CellRefList itemLists; - CellRefList lights; - CellRefList lockpicks; - CellRefList miscItems; - CellRefList npcs; - CellRefList probes; - CellRefList repairs; - CellRefList statics; - CellRefList weapons; - - void load (const ESMStore &store, ESMReader &esm) - { - if (mState!=State_Loaded) - { - if (mState==State_Preloaded) - mIds.clear(); - - std::cout << "loading cell " << cell->getDescription() << std::endl; - - loadRefs (store, esm); - - mState = State_Loaded; - } - } - - void preload (const ESMStore &store, ESMReader &esm) - { - if (mState==State_Unloaded) - { - listRefs (store, esm); - - mState = State_Preloaded; - } - } - - /// Call functor (ref) for each reference. functor must return a bool. Returning - /// false will abort the iteration. - /// \return Iteration completed? - template - bool forEach (Functor& functor) - { - return - forEachImp (functor, activators) && - forEachImp (functor, potions) && - forEachImp (functor, appas) && - forEachImp (functor, armors) && - forEachImp (functor, books) && - forEachImp (functor, clothes) && - forEachImp (functor, containers) && - forEachImp (functor, creatures) && - forEachImp (functor, doors) && - forEachImp (functor, ingreds) && - forEachImp (functor, creatureLists) && - forEachImp (functor, itemLists) && - forEachImp (functor, lights) && - forEachImp (functor, lockpicks) && - forEachImp (functor, miscItems) && - forEachImp (functor, npcs) && - forEachImp (functor, probes) && - forEachImp (functor, repairs) && - forEachImp (functor, statics) && - forEachImp (functor, weapons); - } - - private: - - template - bool forEachImp (Functor& functor, List& list) - { - for (typename List::List::iterator iter (list.list.begin()); iter!=list.list.end(); - ++iter) - if (!functor (iter->ref, iter->mData)) - return false; - - return true; - } - - /// Run through references and store IDs - void listRefs(const ESMStore &store, ESMReader &esm) - { - assert (cell); - - if (cell->context.filename.empty()) - return; // this is a dynamically generated cell -> skipping. - - // Reopen the ESM reader and seek to the right position. - cell->restore (esm); - - CellRef ref; - - // Get each reference in turn - while (cell->getNextRef (esm, ref)) - { - std::string lowerCase; - - std::transform (ref.refID.begin(), ref.refID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - mIds.push_back (lowerCase); - } - - std::sort (mIds.begin(), mIds.end()); - } - - void loadRefs(const ESMStore &store, ESMReader &esm) - { - assert (cell); - - if (cell->context.filename.empty()) - return; // this is a dynamically generated cell -> skipping. - - // Reopen the ESM reader and seek to the right position. - cell->restore(esm); - - CellRef ref; - - // Get each reference in turn - while(cell->getNextRef(esm, ref)) - { - std::string lowerCase; - - std::transform (ref.refID.begin(), ref.refID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - int rec = store.find(ref.refID); - - ref.refID = lowerCase; - - /* We can optimize this further by storing the pointer to the - record itself in store.all, so that we don't need to look it - up again here. However, never optimize. There are infinite - opportunities to do that later. - */ - switch(rec) - { - case REC_ACTI: activators.find(ref, store.activators); break; - case REC_ALCH: potions.find(ref, store.potions); break; - case REC_APPA: appas.find(ref, store.appas); break; - case REC_ARMO: armors.find(ref, store.armors); break; - case REC_BOOK: books.find(ref, store.books); break; - case REC_CLOT: clothes.find(ref, store.clothes); break; - case REC_CONT: containers.find(ref, store.containers); break; - case REC_CREA: creatures.find(ref, store.creatures); break; - case REC_DOOR: doors.find(ref, store.doors); break; - case REC_INGR: ingreds.find(ref, store.ingreds); break; - case REC_LEVC: creatureLists.find(ref, store.creatureLists); break; - case REC_LEVI: itemLists.find(ref, store.itemLists); break; - case REC_LIGH: lights.find(ref, store.lights); break; - case REC_LOCK: lockpicks.find(ref, store.lockpicks); break; - case REC_MISC: miscItems.find(ref, store.miscItems); break; - case REC_NPC_: npcs.find(ref, store.npcs); break; - case REC_PROB: probes.find(ref, store.probes); break; - case REC_REPA: repairs.find(ref, store.repairs); break; - case REC_STAT: statics.find(ref, store.statics); break; - case REC_WEAP: weapons.find(ref, store.weapons); break; - - case 0: std::cout << "Cell reference " + ref.refID + " not found!\n"; break; - default: - std::cout << "WARNING: Ignoring reference '" << ref.refID << "' of unhandled type\n"; - } - } - } - - }; -} - -#endif diff --git a/components/esm_store/reclists.hpp b/components/esm_store/reclists.hpp index 48bf050cd..ffecfc8de 100644 --- a/components/esm_store/reclists.hpp +++ b/components/esm_store/reclists.hpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/components/esm_store/store.hpp b/components/esm_store/store.hpp index 507196a86..991925bd4 100644 --- a/components/esm_store/store.hpp +++ b/components/esm_store/store.hpp @@ -30,7 +30,7 @@ namespace ESMS // Each individual list RecListT activators; - RecListT potions; + RecListWithIDT potions; RecListT appas; RecListT armors; RecListT bodyParts; @@ -47,7 +47,7 @@ namespace ESMS RecListT enchants; RecListT factions; RecListT globals; - RecListT ingreds; + RecListWithIDT ingreds; RecListT creatureLists; RecListT itemLists; RecListT lights; diff --git a/components/files/collections.hpp b/components/files/collections.hpp index 70aaec55e..ed4aafa13 100644 --- a/components/files/collections.hpp +++ b/components/files/collections.hpp @@ -1,8 +1,6 @@ #ifndef COMPONENTS_FILES_COLLECTION_HPP #define COMPONENTS_FILES_COLLECTION_HPP -#include -#include #include #include "multidircollection.hpp" diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 150a4fcd8..ef810fb06 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -15,7 +15,6 @@ namespace Files { static const char* const openmwCfgFile = "openmw.cfg"; -static const char* const pluginsCfgFile = "plugins.cfg"; const char* const mwToken = "?mw?"; const char* const localToken = "?local?"; @@ -27,16 +26,7 @@ ConfigurationManager::ConfigurationManager() { setupTokensMapping(); - mPluginsCfgPath = mFixedPath.getLocalPath() / pluginsCfgFile; - if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) - { - mPluginsCfgPath = mFixedPath.getGlobalPath() / pluginsCfgFile; - if (!boost::filesystem::is_regular_file(mPluginsCfgPath)) - { - std::cerr << "Failed to find " << pluginsCfgFile << " file!" << std::endl; - mPluginsCfgPath.clear(); - } - } + boost::filesystem::create_directories(mFixedPath.getUserPath()); mLogPath = mFixedPath.getUserPath(); } @@ -162,11 +152,6 @@ const boost::filesystem::path& ConfigurationManager::getInstallPath() const return mFixedPath.getInstallPath(); } -const boost::filesystem::path& ConfigurationManager::getPluginsConfigPath() const -{ - return mPluginsCfgPath; -} - const boost::filesystem::path& ConfigurationManager::getLogPath() const { return mLogPath; diff --git a/components/files/configurationmanager.hpp b/components/files/configurationmanager.hpp index af9d02b91..ecbfac664 100644 --- a/components/files/configurationmanager.hpp +++ b/components/files/configurationmanager.hpp @@ -8,7 +8,6 @@ #endif #include -#include #include #include @@ -41,7 +40,6 @@ struct ConfigurationManager const boost::filesystem::path& getLocalDataPath() const; const boost::filesystem::path& getInstallPath() const; - const boost::filesystem::path& getPluginsConfigPath() const; const boost::filesystem::path& getLogPath() const; private: @@ -58,7 +56,6 @@ struct ConfigurationManager FixedPathType mFixedPath; - boost::filesystem::path mPluginsCfgPath; boost::filesystem::path mLogPath; TokensMappingContainer mTokensMapping; diff --git a/components/files/ogreplugin.cpp b/components/files/ogreplugin.cpp new file mode 100644 index 000000000..85fe661de --- /dev/null +++ b/components/files/ogreplugin.cpp @@ -0,0 +1,41 @@ +#include "ogreplugin.hpp" + +#include +#include + +namespace Files { + +bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot) { + // Append plugin suffix if debugging. +#if defined(DEBUG) || defined(_DEBUG) + pluginName = pluginName + OGRE_PLUGIN_DEBUG_SUFFIX; +#endif + +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + std::ostringstream verStream; + verStream << "." << OGRE_VERSION_MAJOR << "." << OGRE_VERSION_MINOR << "." << OGRE_VERSION_PATCH; + pluginName = pluginName + verStream.str(); +#endif + + std::string pluginExt; +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + pluginExt = ".dll"; +#endif +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + pluginExt = ".dylib"; +#endif +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX + pluginExt = ".so"; +#endif + + std::string pluginPath = pluginDir + "/" + pluginName + pluginExt; + if (boost::filesystem::exists(pluginPath)) { + ogreRoot.loadPlugin(pluginPath); + return true; + } + else { + return false; + } +} + +} \ No newline at end of file diff --git a/components/files/ogreplugin.hpp b/components/files/ogreplugin.hpp new file mode 100644 index 000000000..2d56bfb47 --- /dev/null +++ b/components/files/ogreplugin.hpp @@ -0,0 +1,64 @@ +/** + * Open Morrowind - an opensource Elder Scrolls III: Morrowind + * engine implementation. + * + * Copyright (C) 2011 Open Morrowind Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file components/files/ogreplugin.hpp */ + +#ifndef COMPONENTS_FILES_OGREPLUGIN_H +#define COMPONENTS_FILES_OGREPLUGIN_H + +#include + +#include +#include + +namespace Ogre { + class Root; +} + +#if (BOOST_VERSION <= 104500) +namespace boost { +namespace filesystem { +inline path absolute(const path& p, const path& base=current_path()) { + // call obsolete version of this function on older boost + return complete(p, base); +} +} +} +#endif /* (BOOST_VERSION <= 104300) */ + +/** + * \namespace Files + */ +namespace Files { + +/** + * \brief Loads Ogre plugin with given name. + * + * \param pluginDir absolute path to plugins + * \param pluginName plugin name, for example "RenderSystem_GL" + * \param ogreRoot Ogre::Root instance + * + * \return whether plugin was located or not + */ +bool loadOgrePlugin(const std::string &pluginDir, std::string pluginName, Ogre::Root &ogreRoot); + +} + +#endif /* COMPONENTS_FILES_OGREPLUGIN_H */ diff --git a/components/misc/tests/slice_test.cpp b/components/misc/tests/slice_test.cpp index a0ea55311..0d9d7b4ab 100644 --- a/components/misc/tests/slice_test.cpp +++ b/components/misc/tests/slice_test.cpp @@ -2,8 +2,6 @@ using namespace std; -#include - #include "../slice_array.hpp" int main() diff --git a/components/misc/tests/strops_test.cpp b/components/misc/tests/strops_test.cpp index 2a1fdd77d..24ab8a298 100644 --- a/components/misc/tests/strops_test.cpp +++ b/components/misc/tests/strops_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include "../stringops.hpp" diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index d59950132..b9d84b58a 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -25,6 +25,7 @@ #define _NIF_CONTROLLED_H_ #include "extra.hpp" +#include "controller.hpp" namespace Nif { @@ -33,92 +34,104 @@ namespace Nif class Controlled : public Extra { public: - ControllerPtr controller; + ControllerPtr controller; - void read(NIFFile *nif) - { - Extra::read(nif); - controller.read(nif); - } + void read(NIFFile *nif) + { + Extra::read(nif); + controller.read(nif); + } + + void post(NIFFile *nif) + { + Extra::post(nif); + controller.post(nif); + } }; /// Has name, extra-data and controller class Named : public Controlled { public: - Misc::SString name; + std::string name; - void read(NIFFile *nif) - { - name = nif->getString(); - Controlled::read(nif); - } + void read(NIFFile *nif) + { + name = nif->getString(); + Controlled::read(nif); + } }; typedef Named NiSequenceStreamHelper; class NiParticleGrowFade : public Controlled { public: - void read(NIFFile *nif) - { - Controlled::read(nif); + void read(NIFFile *nif) + { + Controlled::read(nif); - // Two floats. - nif->skip(8); - } + // Two floats. + nif->skip(8); + } }; class NiParticleColorModifier : public Controlled { public: - NiColorDataPtr data; + NiColorDataPtr data; - void read(NIFFile *nif) - { - Controlled::read(nif); - data.read(nif); - } + void read(NIFFile *nif) + { + Controlled::read(nif); + data.read(nif); + } + + void post(NIFFile *nif) + { + Controlled::post(nif); + data.post(nif); + } }; class NiGravity : public Controlled { public: - void read(NIFFile *nif) - { - Controlled::read(nif); + void read(NIFFile *nif) + { + Controlled::read(nif); - // two floats, one int, six floats - nif->skip(9*4); - } + // two floats, one int, six floats + nif->skip(9*4); + } }; // NiPinaColada class NiPlanarCollider : public Controlled { public: - void read(NIFFile *nif) - { - Controlled::read(nif); + void read(NIFFile *nif) + { + Controlled::read(nif); - // (I think) 4 floats + 4 vectors - nif->skip(4*16); - } + // (I think) 4 floats + 4 vectors + nif->skip(4*16); + } }; class NiParticleRotation : public Controlled { public: - void read(NIFFile *nif) - { - Controlled::read(nif); + void read(NIFFile *nif) + { + Controlled::read(nif); - /* - byte (0 or 1) - float (1) - float*3 - */ - nif->skip(17); - } + /* + byte (0 or 1) + float (1) + float*3 + */ + nif->skip(17); + } }; } // Namespace diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index d6fb22255..cbc19cd8f 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -34,136 +34,187 @@ namespace Nif class Controller : public Record { public: - ControllerPtr next; - int flags; - float frequency, phase; - float timeStart, timeStop; - ControlledPtr target; + ControllerPtr next; + int flags; + float frequency, phase; + float timeStart, timeStop; + ControlledPtr target; - void read(NIFFile *nif) - { - next.read(nif); + void read(NIFFile *nif) + { + next.read(nif); - flags = nif->getShort(); + flags = nif->getUShort(); - frequency = nif->getFloat(); - phase = nif->getFloat(); - timeStart = nif->getFloat(); - timeStop = nif->getFloat(); + frequency = nif->getFloat(); + phase = nif->getFloat(); + timeStart = nif->getFloat(); + timeStop = nif->getFloat(); - target.read(nif); - } + target.read(nif); + } + + void post(NIFFile *nif) + { + Record::post(nif); + next.post(nif); + target.post(nif); + } }; class NiBSPArrayController : public Controller { public: - void read(NIFFile *nif) - { - Controller::read(nif); + void read(NIFFile *nif) + { + Controller::read(nif); - // At the moment, just skip it all - nif->skip(111); - int s = nif->getShort(); - nif->skip(15 + s*40); - } + // At the moment, just skip it all + nif->skip(111); + int s = nif->getUShort(); + nif->skip(15 + s*40); + } }; typedef NiBSPArrayController NiParticleSystemController; class NiMaterialColorController : public Controller { public: - NiPosDataPtr data; + NiPosDataPtr data; - void read(NIFFile *nif) - { - Controller::read(nif); - data.read(nif); - } + void read(NIFFile *nif) + { + Controller::read(nif); + data.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } }; class NiPathController : public Controller { public: - NiPosDataPtr posData; - NiFloatDataPtr floatData; + NiPosDataPtr posData; + NiFloatDataPtr floatData; - void read(NIFFile *nif) - { - Controller::read(nif); + void read(NIFFile *nif) + { + Controller::read(nif); - /* - int = 1 - 2xfloat - short = 0 or 1 - */ - nif->skip(14); - posData.read(nif); - floatData.read(nif); - } + /* + int = 1 + 2xfloat + short = 0 or 1 + */ + nif->skip(14); + posData.read(nif); + floatData.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + + posData.post(nif); + floatData.post(nif); + } }; class NiUVController : public Controller { public: - NiUVDataPtr data; + NiUVDataPtr data; - void read(NIFFile *nif) - { - Controller::read(nif); + void read(NIFFile *nif) + { + Controller::read(nif); - nif->getShort(); // always 0 - data.read(nif); - } + nif->getUShort(); // always 0 + data.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } }; class NiKeyframeController : public Controller { public: - NiKeyframeDataPtr data; + NiKeyframeDataPtr data; - void read(NIFFile *nif) - { - Controller::read(nif); - data.read(nif); - } + void read(NIFFile *nif) + { + Controller::read(nif); + data.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } }; class NiAlphaController : public Controller { public: - NiFloatDataPtr data; + NiFloatDataPtr data; - void read(NIFFile *nif) - { - Controller::read(nif); - data.read(nif); - } + void read(NIFFile *nif) + { + Controller::read(nif); + data.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } }; class NiGeomMorpherController : public Controller { public: - NiMorphDataPtr data; + NiMorphDataPtr data; - void read(NIFFile *nif) - { - Controller::read(nif); - data.read(nif); - nif->getByte(); // always 0 - } + void read(NIFFile *nif) + { + Controller::read(nif); + data.read(nif); + nif->getChar(); // always 0 + } + + void post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } }; class NiVisController : public Controller { public: - NiVisDataPtr data; + NiVisDataPtr data; - void read(NIFFile *nif) - { - Controller::read(nif); - data.read(nif); - } + void read(NIFFile *nif) + { + Controller::read(nif); + data.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + data.post(nif); + } }; } // Namespace diff --git a/components/nif/data.hpp b/components/nif/data.hpp index df9079758..63df23b27 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -25,8 +25,9 @@ #define _NIF_DATA_H_ #include "controlled.hpp" -#include -#include + +#include +#include namespace Nif { @@ -34,794 +35,389 @@ namespace Nif class NiSourceTexture : public Named { public: + // Is this an external (references a separate texture file) or + // internal (data is inside the nif itself) texture? + bool external; - // Is this an external (references a separate texture file) or - // internal (data is inside the nif itself) texture? - bool external; + std::string filename; // In case of external textures + NiPixelDataPtr data; // In case of internal textures - Misc::SString filename; // In case of external textures - NiPixelDataPtr data; // In case of internal textures + /* Pixel layout + 0 - Palettised + 1 - High color 16 + 2 - True color 32 + 3 - Compressed + 4 - Bumpmap + 5 - Default */ + int pixel; - /* Pixel layout - 0 - Palettised - 1 - High color 16 - 2 - True color 32 - 3 - Compressed - 4 - Bumpmap - 5 - Default */ - int pixel; + /* Mipmap format + 0 - no + 1 - yes + 2 - default */ + int mipmap; - /* Mipmap format - 0 - no - 1 - yes - 2 - default */ - int mipmap; + /* Alpha + 0 - none + 1 - binary + 2 - smooth + 3 - default (use material alpha, or multiply material with texture if present) + */ + int alpha; - /* Alpha - 0 - none - 1 - binary - 2 - smooth - 3 - default (use material alpha, or multiply material with texture if present) - */ - int alpha; + void read(NIFFile *nif) + { + Named::read(nif); - void read(NIFFile *nif) - { - Named::read(nif); + external = !!nif->getChar(); + if(external) + filename = nif->getString(); + else + { + nif->getChar(); // always 1 + data.read(nif); + } - external = !!nif->getByte(); + pixel = nif->getInt(); + mipmap = nif->getInt(); + alpha = nif->getInt(); - if(external) filename = nif->getString(); - else - { - nif->getByte(); // always 1 - data.read(nif); - } + nif->getChar(); // always 1 + } - pixel = nif->getInt(); - mipmap = nif->getInt(); - alpha = nif->getInt(); - - nif->getByte(); // always 1 - } + void post(NIFFile *nif) + { + Named::post(nif); + data.post(nif); + } }; // Common ancestor for several data classes class ShapeData : public Record { public: - Misc::FloatArray vertices, normals, colors, uvlist; - const Vector *center; - float radius; + std::vector vertices, normals; + std::vector colors; + std::vector< std::vector > uvlist; + Ogre::Vector3 center; + float radius; - void read(NIFFile *nif) - { - int verts = nif->getShort(); + void read(NIFFile *nif) + { + int verts = nif->getUShort(); - if(nif->getInt()) - vertices = nif->getFloatLen(verts*3); + if(nif->getInt()) + nif->getVector3s(vertices, verts); - if(nif->getInt()) - normals = nif->getFloatLen(verts*3); + if(nif->getInt()) + nif->getVector3s(normals, verts); - center = nif->getVector(); - radius = nif->getFloat(); + center = nif->getVector3(); + radius = nif->getFloat(); - if(nif->getInt()) - colors = nif->getFloatLen(verts*4); + if(nif->getInt()) + nif->getVector4s(colors, verts); - int uvs = nif->getShort(); + // Only the first 6 bits are used as a count. I think the rest are + // flags of some sort. + int uvs = nif->getUShort(); + uvs &= 0x3f; - // Only the first 6 bits are used as a count. I think the rest are - // flags of some sort. - uvs &= 0x3f; - - if(nif->getInt()) - uvlist = nif->getFloatLen(uvs*verts*2); - } + if(nif->getInt()) + { + uvlist.resize(uvs); + for(int i = 0;i < uvs;i++) + nif->getVector2s(uvlist[i], verts); + } + } }; class NiTriShapeData : public ShapeData { public: - // Triangles, three vertex indices per triangle - Misc::SliceArray triangles; + // Triangles, three vertex indices per triangle + std::vector triangles; - void read(NIFFile *nif) - { - ShapeData::read(nif); + void read(NIFFile *nif) + { + ShapeData::read(nif); - int tris = nif->getShort(); - if(tris) - { - // We have three times as many vertices as triangles, so this - // is always equal to tris*3. - int cnt = nif->getInt(); - triangles = nif->getArrayLen(cnt); - } + int tris = nif->getUShort(); + if(tris) + { + // We have three times as many vertices as triangles, so this + // is always equal to tris*3. + int cnt = nif->getInt(); + nif->getShorts(triangles, cnt); + } - // Read the match list, which lists the vertices that are equal to - // vertices. We don't actually need need this for anything, so - // just skip it. - int verts = nif->getShort(); - if(verts) - { + // Read the match list, which lists the vertices that are equal to + // vertices. We don't actually need need this for anything, so + // just skip it. + int verts = nif->getUShort(); for(int i=0;igetShort(); - nif->skip(num*sizeof(short)); - } - } - } + int num = nif->getUShort(); + nif->skip(num * sizeof(short)); + } + } }; class NiAutoNormalParticlesData : public ShapeData { public: - int activeCount; + int activeCount; - void read(NIFFile *nif) - { - ShapeData::read(nif); + void read(NIFFile *nif) + { + ShapeData::read(nif); - // Should always match the number of vertices - activeCount = nif->getShort(); + // Should always match the number of vertices + activeCount = nif->getUShort(); - // Skip all the info, we don't support particles yet - nif->getFloat(); // Active radius ? - nif->getShort(); // Number of valid entries in the following arrays ? + // Skip all the info, we don't support particles yet + nif->getFloat(); // Active radius ? + nif->getUShort(); // Number of valid entries in the following arrays ? - if(nif->getInt()) - // Particle sizes - nif->getFloatLen(activeCount); - } + if(nif->getInt()) + { + // Particle sizes + nif->skip(activeCount * sizeof(float)); + } + } }; class NiRotatingParticlesData : public NiAutoNormalParticlesData { public: - void read(NIFFile *nif) - { - NiAutoNormalParticlesData::read(nif); + void read(NIFFile *nif) + { + NiAutoNormalParticlesData::read(nif); - if(nif->getInt()) - // Rotation quaternions. I THINK activeCount is correct here, - // but verts (vertex number) might also be correct, if there is - // any case where the two don't match. - nif->getArrayLen(activeCount); - } + if(nif->getInt()) + { + // Rotation quaternions. I THINK activeCount is correct here, + // but verts (vertex number) might also be correct, if there is + // any case where the two don't match. + nif->skip(activeCount * 4*sizeof(float)); + } + } }; class NiPosData : public Record { public: - void read(NIFFile *nif) - { - int count = nif->getInt(); - int type = nif->getInt(); - if(type != 1 && type != 2) - nif->fail("Cannot handle NiPosData type"); + Vector3KeyList mKeyList; - // TODO: Could make structs of these. Seems to be identical to - // translation in NiKeyframeData. - for(int i=0; igetFloat(); - nif->getVector(); // This isn't really shared between type 1 - // and type 2, most likely - if(type == 2) - { - nif->getVector(); - nif->getVector(); - } - } - } + void read(NIFFile *nif) + { + mKeyList.read(nif); + } }; class NiUVData : public Record { public: - void read(NIFFile *nif) - { - // TODO: This is claimed to be a "float animation key", which is - // also used in FloatData and KeyframeData. We could probably - // reuse and refactor a lot of this if we actually use it at some - // point. + FloatKeyList mKeyList[4]; - for(int i=0; i<2; i++) - { - int count = nif->getInt(); - - if(count) - { - nif->getInt(); // always 2 - nif->getArrayLen(count); // Really one time float + one vector - } - } - // Always 0 - nif->getInt(); - nif->getInt(); - } + void read(NIFFile *nif) + { + for(int i = 0;i < 4;i++) + mKeyList[i].read(nif); + } }; class NiFloatData : public Record { public: - void read(NIFFile *nif) - { - int count = nif->getInt(); - nif->getInt(); // always 2 - nif->getArrayLen(count); // Really one time float + one vector - } + FloatKeyList mKeyList; + + void read(NIFFile *nif) + { + mKeyList.read(nif); + } }; class NiPixelData : public Record { public: - unsigned int rmask, gmask, bmask, amask; - int bpp, mips; + unsigned int rmask, gmask, bmask, amask; + int bpp, mips; - void read(NIFFile *nif) - { - nif->getInt(); // always 0 or 1 + void read(NIFFile *nif) + { + nif->getInt(); // always 0 or 1 - rmask = nif->getInt(); // usually 0xff - gmask = nif->getInt(); // usually 0xff00 - bmask = nif->getInt(); // usually 0xff0000 - amask = nif->getInt(); // usually 0xff000000 or zero + rmask = nif->getInt(); // usually 0xff + gmask = nif->getInt(); // usually 0xff00 + bmask = nif->getInt(); // usually 0xff0000 + amask = nif->getInt(); // usually 0xff000000 or zero - bpp = nif->getInt(); + bpp = nif->getInt(); - // Unknown - nif->skip(12); + // Unknown + nif->skip(12); - mips = nif->getInt(); + mips = nif->getInt(); - // Bytes per pixel, should be bpp * 8 - /*int bytes =*/ nif->getInt(); + // Bytes per pixel, should be bpp * 8 + /*int bytes =*/ nif->getInt(); - for(int i=0; igetInt(); - /*int y =*/ nif->getInt(); - /*int offset =*/ nif->getInt(); - } + for(int i=0; igetInt(); + /*int y =*/ nif->getInt(); + /*int offset =*/ nif->getInt(); + } - // Skip the data - unsigned int dataSize = nif->getInt(); - nif->skip(dataSize); - } + // Skip the data + unsigned int dataSize = nif->getInt(); + nif->skip(dataSize); + } }; class NiColorData : public Record { public: - struct ColorData - { - float time; - Vector4 rgba; - }; + Vector4KeyList mKeyList; - void read(NIFFile *nif) - { - int count = nif->getInt(); - nif->getInt(); // always 1 - - // Skip the data - assert(sizeof(ColorData) == 4*5); - nif->skip(sizeof(ColorData) * count); - } + void read(NIFFile *nif) + { + mKeyList.read(nif); + } }; class NiVisData : public Record { public: - void read(NIFFile *nif) - { - int count = nif->getInt(); - /* - Each VisData consists of: + struct VisData { float time; - byte isSet; + char isSet; + }; - If you implement this, make sure you use a packed struct - (sizeof==5), or read each element individually. - */ - nif->skip(count*5); - } + void read(NIFFile *nif) + { + int count = nif->getInt(); + + /* Skip VisData */ + nif->skip(count*5); + } }; class NiSkinInstance : public Record { public: - NiSkinDataPtr data; - NodePtr root; - NodeList bones; + NiSkinDataPtr data; + NodePtr root; + NodeList bones; - void read(NIFFile *nif) - { - data.read(nif); - root.read(nif); - bones.read(nif); + void read(NIFFile *nif) + { + data.read(nif); + root.read(nif); + bones.read(nif); + } - if(data.empty() || root.empty()) - nif->fail("NiSkinInstance missing root or data"); - } - - void post(NIFFile *nif); + void post(NIFFile *nif); }; class NiSkinData : public Record { public: - // This is to make sure the structs are packed, ie. that the - // compiler doesn't mess them up with extra alignment bytes. -#pragma pack(push) -#pragma pack(1) - - struct BoneTrafo - { - Matrix rotation; // Rotation offset from bone? - Vector trans; // Translation - float scale; // Probably scale (always 1) - }; - struct BoneTrafoCopy - { - Ogre::Quaternion rotation; - Ogre::Vector3 trans; - float scale; - }; - - struct VertWeight - { - short vertex; - float weight; - }; -#pragma pack(pop) - - struct BoneInfo - { - const BoneTrafo *trafo; - const Vector4 *unknown; - Misc::SliceArray weights; - }; - struct BoneInfoCopy - { - std::string bonename; - unsigned short bonehandle; - BoneTrafoCopy trafo; - Vector4 unknown; - //std::vector weights; - }; - struct IndividualWeight - { - float weight; - unsigned int boneinfocopyindex; - }; - - const BoneTrafo *trafo; - std::vector bones; - - void read(NIFFile *nif) - { - assert(sizeof(BoneTrafo) == 4*(9+3+1)); - assert(sizeof(VertWeight) == 6); - - trafo = nif->getPtr(); - - int boneNum = nif->getInt(); - nif->getInt(); // -1 - - bones.resize(boneNum); - - for(int i=0;igetPtr(); - bi.unknown = nif->getVector4(); - - // Number of vertex weights - int count = nif->getShort(); - bi.weights = nif->getArrayLen(count); - } - } -}; - -class NiMorphData : public Record -{ - float startTime; - float stopTime; - std::vector initialVertices; - std::vector > relevantTimes; - std::vector > relevantData; - std::vector > additionalVertices; - - -public: - float getStartTime(){ - return startTime; - } - float getStopTime(){ - return stopTime; - } - void setStartTime(float time){ - startTime = time; - } - - void setStopTime(float time){ - stopTime = time; - } - std::vector getInitialVertices(){ - return initialVertices; - } - std::vector > getRelevantData(){ - return relevantData; - } - std::vector > getRelevantTimes(){ - return relevantTimes; - } - std::vector > getAdditionalVertices(){ - return additionalVertices; - } - -void read(NIFFile *nif) - { - int morphCount = nif->getInt(); - int vertCount = nif->getInt(); - nif->getByte(); - int magic = nif->getInt(); - /*int type =*/ nif->getInt(); - for(int i = 0; i < vertCount; i++){ - - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - initialVertices.push_back(Ogre::Vector3(x, y, z)); - } - - for(int i=1; igetInt(); - /*type =*/ nif->getInt(); - std::vector current; - std::vector currentTime; - for(int i = 0; i < magic; i++){ - // Time, data, forward, backward tangents - float time = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - current.push_back(Ogre::Vector3(x,y,z)); - currentTime.push_back(time); - //nif->getFloatLen(4*magic); - } - if(magic){ - relevantData.push_back(current); - relevantTimes.push_back(currentTime); - } - std::vector verts; - for(int i = 0; i < vertCount; i++){ - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - verts.push_back(Ogre::Vector3(x, y, z)); - } - additionalVertices.push_back(verts); - } - } + Ogre::Matrix3 rotation; // Rotation offset from bone? + Ogre::Vector3 trans; // Translation + float scale; // Probably scale (always 1) + }; + + struct VertWeight + { + short vertex; + float weight; + }; + + struct BoneInfo + { + BoneTrafo trafo; + Ogre::Vector4 unknown; + std::vector weights; + }; + + BoneTrafo trafo; + std::vector bones; + + void read(NIFFile *nif) + { + trafo.rotation = nif->getMatrix3(); + trafo.trans = nif->getVector3(); + trafo.scale = nif->getFloat(); + + int boneNum = nif->getInt(); + nif->getInt(); // -1 + + bones.resize(boneNum); + for(int i=0;igetMatrix3(); + bi.trafo.trans = nif->getVector3(); + bi.trafo.scale = nif->getFloat(); + bi.unknown = nif->getVector4(); + + // Number of vertex weights + bi.weights.resize(nif->getUShort()); + for(size_t j = 0;j < bi.weights.size();j++) + { + bi.weights[j].vertex = nif->getUShort(); + bi.weights[j].weight = nif->getFloat(); + } + } + } +}; + +struct NiMorphData : public Record +{ + struct MorphData { + FloatKeyList mData; + std::vector mVertices; + }; + std::vector mMorphs; + + void read(NIFFile *nif) + { + int morphCount = nif->getInt(); + int vertCount = nif->getInt(); + nif->getChar(); + + mMorphs.resize(morphCount); + for(int i = 0;i < morphCount;i++) + { + mMorphs[i].mData.read(nif, true); + + mMorphs[i].mVertices.resize(vertCount); + for(int j = 0;j < vertCount;j++) + mMorphs[i].mVertices[j] = nif->getVector3(); + } + } }; -class NiKeyframeData : public Record +struct NiKeyframeData : public Record { - std::string bonename; - //Rotations - std::vector quats; - std::vector tbc; - std::vector rottime; - float startTime; - float stopTime; - int rtype; - - //Translations - std::vector translist1; - std::vector translist2; - std::vector translist3; - std::vector transtbc; - std::vector transtime; - int ttype; - - //Scalings - - std::vector scalefactor; - std::vector scaletime; - std::vector forwards; - std::vector backwards; - std::vector tbcscale; - int stype; - - - -public: - void clone(NiKeyframeData c) - { - quats = c.getQuat(); - tbc = c.getrTbc(); - rottime = c.getrTime(); - - //types - ttype = c.getTtype(); - rtype = c.getRtype(); - stype = c.getStype(); - - - translist1 = c.getTranslist1(); - translist2 = c.getTranslist2(); - translist3 = c.getTranslist3(); - - transtime = c.gettTime(); - - bonename = c.getBonename(); - - - } - - void setBonename(std::string bone) - { - bonename = bone; - } - void setStartTime(float start) - { - startTime = start; - } - void setStopTime(float end) - { - stopTime = end; - } - void read(NIFFile *nif) - { - // Rotations first - int count = nif->getInt(); - //std::vector quat(count); - //std::vector rottime(count); - if(count) - { - - //TYPE1 LINEAR_KEY - //TYPE2 QUADRATIC_KEY - //TYPE3 TBC_KEY - //TYPE4 XYZ_ROTATION_KEY - //TYPE5 UNKNOWN_KEY - rtype = nif->getInt(); - //std::cout << "Count: " << count << "Type: " << type << "\n"; - - if(rtype == 1) - { - //We need to actually read in these values instead of skipping them - //nif->skip(count*4*5); // time + quaternion - for (int i = 0; i < count; i++) { - float time = nif->getFloat(); - float w = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - Ogre::Quaternion quat = Ogre::Quaternion(Ogre::Real(w), Ogre::Real(x), Ogre::Real(y), Ogre::Real(z)); - quats.push_back(quat); - rottime.push_back(time); - //if(time == 0.0 || time > 355.5) - // std::cout <<"Time:" << time << "W:" << w <<"X:" << x << "Y:" << y << "Z:" << z << "\n"; - } - } - else if(rtype == 3) - { //Example - node 116 in base_anim.nif - for (int i = 0; i < count; i++) { - float time = nif->getFloat(); - float w = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - - float tbcx = nif->getFloat(); - float tbcy = nif->getFloat(); - float tbcz = nif->getFloat(); - Ogre::Quaternion quat = Ogre::Quaternion(Ogre::Real(w), Ogre::Real(x), Ogre::Real(y), Ogre::Real(z)); - Ogre::Vector3 vec = Ogre::Vector3(tbcx, tbcy, tbcz); - quats.push_back(quat); - rottime.push_back(time); - tbc.push_back(vec); - //if(time == 0.0 || time > 355.5) - // std::cout <<"Time:" << time << "W:" << w <<"X:" << x << "Y:" << y << "Z:" << z << "\n"; - } - - //nif->skip(count*4*8); // rot1 + tension+bias+continuity - } - else if(rtype == 4) - { - for(int j=0;jgetFloat(); // time - for(int i=0; i<3; i++) - { - int cnt = nif->getInt(); - int type = nif->getInt(); - if(type == 1) - nif->skip(cnt*4*2); // time + unknown - else if(type == 2) - nif->skip(cnt*4*4); // time + unknown vector - else nif->fail("Unknown sub-rotation type"); - } - } - } - else nif->fail("Unknown rotation type in NiKeyframeData"); - } - //first = false; - - // Then translation - count = nif->getInt(); - - if(count) - { - ttype = nif->getInt(); - - //std::cout << "TransCount:" << count << " Type: " << type << "\n"; - if(ttype == 1) { - for (int i = 0; i < count; i++) { - float time = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - Ogre::Vector3 trans = Ogre::Vector3(x, y, z); - translist1.push_back(trans); - transtime.push_back(time); - } - //nif->getFloatLen(count*4); // time + translation - } - else if(ttype == 2) - { //Example - node 116 in base_anim.nif - for (int i = 0; i < count; i++) { - float time = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - float x2 = nif->getFloat(); - float y2 = nif->getFloat(); - float z2 = nif->getFloat(); - float x3 = nif->getFloat(); - float y3 = nif->getFloat(); - float z3 = nif->getFloat(); - Ogre::Vector3 trans = Ogre::Vector3(x, y, z); - Ogre::Vector3 trans2 = Ogre::Vector3(x2, y2, z2); - Ogre::Vector3 trans3 = Ogre::Vector3(x3, y3, z3); - transtime.push_back(time); - translist1.push_back(trans); - translist2.push_back(trans2); - translist3.push_back(trans3); - } - - //nif->getFloatLen(count*10); // trans1 + forward + backward - } - else if(ttype == 3){ - for (int i = 0; i < count; i++) { - float time = nif->getFloat(); - float x = nif->getFloat(); - float y = nif->getFloat(); - float z = nif->getFloat(); - float t = nif->getFloat(); - float b = nif->getFloat(); - float c = nif->getFloat(); - Ogre::Vector3 trans = Ogre::Vector3(x, y, z); - Ogre::Vector3 tbc = Ogre::Vector3(t, b, c); - translist1.push_back(trans); - transtbc.push_back(tbc); - transtime.push_back(time); - } - //nif->getFloatLen(count*7); // trans1 + tension,bias,continuity - } - else nif->fail("Unknown translation type"); - } - - // Finally, scalings - count = nif->getInt(); - if(count) - { - stype = nif->getInt(); - - - for(int i = 0; i < count; i++){ - - - //int size = 0; - if(stype >= 1 && stype < 4) - { - float time = nif->getFloat(); - float scale = nif->getFloat(); - scaletime.push_back(time); - scalefactor.push_back(scale); - //size = 2; // time+scale - } - else nif->fail("Unknown scaling type"); - if(stype == 2){ - //size = 4; // 1 + forward + backward (floats) - float forward = nif->getFloat(); - float backward = nif->getFloat(); - forwards.push_back(forward); - backwards.push_back(backward); - } - else if(stype == 3){ - float tbcx = nif->getFloat(); - float tbcy = nif->getFloat(); - float tbcz = nif->getFloat(); - Ogre::Vector3 vec = Ogre::Vector3(tbcx, tbcy, tbcz); - tbcscale.push_back(vec); - - //size = 5; // 1 + tbc - } - - } - } - else - stype = 0; - } - int getRtype(){ - return rtype; - } - int getStype(){ - return stype; - } - int getTtype(){ - return ttype; - } - float getStartTime(){ - return startTime; - } - float getStopTime(){ - return stopTime; - } - std::vector getQuat(){ - return quats; - } - std::vector getrTbc(){ - return tbc; - } - std::vector getrTime(){ - return rottime; - } - - std::vector getTranslist1(){ - return translist1; - } - std::vector getTranslist2(){ - return translist2; - } - std::vector getTranslist3(){ - return translist3; - } - std::vector gettTime(){ - return transtime; - } - std::vector getScalefactor(){ - return scalefactor; - } - std::vector getForwards(){ - return forwards; - } - std::vector getBackwards(){ - return backwards; - } - std::vector getScaleTbc(){ - return tbcscale; - } - - std::vector getsTime(){ - return scaletime; - } - std::string getBonename(){ return bonename; - } - + QuaternionKeyList mRotations; + Vector3KeyList mTranslations; + FloatKeyList mScales; + void read(NIFFile *nif) + { + mRotations.read(nif); + mTranslations.read(nif); + mScales.read(nif); + } }; } // Namespace diff --git a/components/nif/effect.hpp b/components/nif/effect.hpp index b0cc64228..850415dad 100644 --- a/components/nif/effect.hpp +++ b/components/nif/effect.hpp @@ -35,57 +35,70 @@ typedef Node Effect; // NiPointLight and NiSpotLight? struct NiLight : Effect { - struct SLight - { - float dimmer; - Vector ambient; - Vector diffuse; - Vector specular; - }; + struct SLight + { + float dimmer; + Ogre::Vector3 ambient; + Ogre::Vector3 diffuse; + Ogre::Vector3 specular; - const SLight *light; + void read(NIFFile *nif) + { + dimmer = nif->getFloat(); + ambient = nif->getVector3(); + diffuse = nif->getVector3(); + specular = nif->getVector3(); + } + }; + SLight light; - void read(NIFFile *nif) - { - Effect::read(nif); + void read(NIFFile *nif) + { + Effect::read(nif); - nif->getInt(); // 1 - nif->getInt(); // 1? - light = nif->getPtr(); - } + nif->getInt(); // 1 + nif->getInt(); // 1? + light.read(nif); + } }; struct NiTextureEffect : Effect { - NiSourceTexturePtr texture; + NiSourceTexturePtr texture; - void read(NIFFile *nif) - { - Effect::read(nif); + void read(NIFFile *nif) + { + Effect::read(nif); - int tmp = nif->getInt(); - if(tmp) nif->getInt(); // always 1? + int tmp = nif->getInt(); + if(tmp) nif->getInt(); // always 1? - /* - 3 x Vector4 = [1,0,0,0] - int = 2 - int = 0 or 3 - int = 2 - int = 2 - */ - nif->skip(16*4); + /* + 3 x Vector4 = [1,0,0,0] + int = 2 + int = 0 or 3 + int = 2 + int = 2 + */ + nif->skip(16*4); - texture.read(nif); + texture.read(nif); - /* - byte = 0 - vector4 = [1,0,0,0] - short = 0 - short = -75 - short = 0 - */ - nif->skip(23); - } + /* + byte = 0 + vector4 = [1,0,0,0] + short = 0 + short = -75 + short = 0 + */ + nif->skip(23); + } + + void post(NIFFile *nif) + { + Effect::post(nif); + texture.post(nif); + } }; } // Namespace diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index eec1aa7b4..35781dbf5 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -38,70 +38,70 @@ namespace Nif class Extra : public Record { public: - ExtraPtr extra; + ExtraPtr extra; - void read(NIFFile *nif) { extra.read(nif); } + void read(NIFFile *nif) { extra.read(nif); } + void post(NIFFile *nif) { extra.post(nif); } }; class NiVertWeightsExtraData : public Extra { public: - void read(NIFFile *nif) - { - Extra::read(nif); + void read(NIFFile *nif) + { + Extra::read(nif); - // We should have s*4+2 == i, for some reason. Might simply be the - // size of the rest of the record, unhelpful as that may be. - /*int i =*/ nif->getInt(); - int s = nif->getShort(); // number of vertices + // We should have s*4+2 == i, for some reason. Might simply be the + // size of the rest of the record, unhelpful as that may be. + /*int i =*/ nif->getInt(); + int s = nif->getUShort(); - nif->getFloatLen(s); // vertex weights I guess - } + nif->skip(s * sizeof(float)); // vertex weights I guess + } }; class NiTextKeyExtraData : public Extra { public: - struct TextKey - { - float time; - Misc::SString text; - }; + struct TextKey + { + float time; + std::string text; + }; + std::vector list; - std::vector list; + void read(NIFFile *nif) + { + Extra::read(nif); - void read(NIFFile *nif) - { - Extra::read(nif); + nif->getInt(); // 0 - nif->getInt(); // 0 - - int keynum = nif->getInt(); - list.resize(keynum); - for(int i=0; igetFloat(); - list[i].text = nif->getString(); - } - } + int keynum = nif->getInt(); + list.resize(keynum); + for(int i=0; igetFloat(); + list[i].text = nif->getString(); + } + } }; class NiStringExtraData : public Extra { public: - /* Two known meanings: - "MRK" - marker, only visible in the editor, not rendered in-game - "NCO" - no collision - */ - Misc::SString string; + /* Two known meanings: + "MRK" - marker, only visible in the editor, not rendered in-game + "NCO" - no collision + */ + std::string string; - void read(NIFFile *nif) - { - Extra::read(nif); + void read(NIFFile *nif) + { + Extra::read(nif); - nif->getInt(); // size of string + 4. Really useful... - string = nif->getString(); - } + nif->getInt(); // size of string + 4. Really useful... + string = nif->getString(); + } }; } // Namespace diff --git a/components/nif/nif_file.cpp b/components/nif/nif_file.cpp index 80ea7a0b7..3313d89ab 100644 --- a/components/nif/nif_file.cpp +++ b/components/nif/nif_file.cpp @@ -46,8 +46,8 @@ using namespace Misc; void NIFFile::parse() { // Check the header string - const char* head = getString(40); - if(!begins(head, "NetImmerse File Format")) + std::string head = getString(40); + if(head.compare(0, 22, "NetImmerse File Format") != 0) fail("Invalid NIF header"); // Get BCD version @@ -70,7 +70,7 @@ void NIFFile::parse() for(int i=0;irecType != RC_MISSING); @@ -190,17 +190,37 @@ void NIFFile::parse() void NiSkinInstance::post(NIFFile *nif) { - int bnum = bones.length(); - if(bnum != static_cast (data->bones.size())) - nif->fail("Mismatch in NiSkinData bone count"); + data.post(nif); + root.post(nif); + bones.post(nif); - root->makeRootBone(data->trafo); + if(data.empty() || root.empty()) + nif->fail("NiSkinInstance missing root or data"); - for(int i=0; ibones.size()) + nif->fail("Mismatch in NiSkinData bone count"); + + root->makeRootBone(&data->trafo); + + for(size_t i=0; ifail("Oops: Missing bone! Don't know how to handle this."); - - bones[i].makeBone(i, data->bones[i]); + if(bones[i].empty()) + nif->fail("Oops: Missing bone! Don't know how to handle this."); + bones[i]->makeBone(i, data->bones[i]); } } + +Ogre::Matrix4 Node::getLocalTransform() +{ + Ogre::Matrix4 mat4(Ogre::Matrix4::IDENTITY); + mat4.makeTransform(trafo.pos, Ogre::Vector3(trafo.scale), Ogre::Quaternion(trafo.rotation)); + return mat4; +} + +Ogre::Matrix4 Node::getWorldTransform() +{ + if(parent != NULL) + return parent->getWorldTransform() * getLocalTransform(); + return getLocalTransform(); +} diff --git a/components/nif/nif_file.hpp b/components/nif/nif_file.hpp index 951ae1f75..a4eaa8990 100644 --- a/components/nif/nif_file.hpp +++ b/components/nif/nif_file.hpp @@ -24,134 +24,294 @@ #ifndef _NIF_FILE_H_ #define _NIF_FILE_H_ -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include +#include + +#include #include "record.hpp" #include "nif_types.hpp" -using namespace Mangle::Stream; - namespace Nif { class NIFFile { - enum NIFVersion - { - VER_MW = 0x04000002 // Morrowind NIFs + enum NIFVersion { + VER_MW = 0x04000002 // Morrowind NIFs }; - /// Nif file version - int ver; + /// Nif file version + int ver; - /// Input stream - StreamPtr inp; + /// Input stream + Ogre::DataStreamPtr inp; - /// File name, used for error messages - std::string filename; + /// File name, used for error messages + std::string filename; - /// Record list - std::vector records; + /// Record list + std::vector records; - /// Parse the file - void parse(); + /// Parse the file + void parse(); - public: - /// Used for error handling - void fail(const std::string &msg) + uint8_t read_byte() { - std::string err = "NIFFile Error: " + msg; - err += "\nFile: " + filename; - throw std::runtime_error(err); + uint8_t byte; + if(inp->read(&byte, 1) != 1) return 0; + return byte; + } + uint16_t read_le16() + { + uint8_t buffer[2]; + if(inp->read(buffer, 2) != 2) return 0; + return buffer[0] | (buffer[1]<<8); + } + uint32_t read_le32() + { + uint8_t buffer[4]; + if(inp->read(buffer, 4) != 4) return 0; + return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); + } + float read_le32f() + { + union { + uint32_t i; + float f; + } u = { read_le32() }; + return u.f; } - /// Open a NIF stream. The name is used for error messages. - NIFFile(StreamPtr nif, const std::string &name) - : filename(name) +public: + /// Used for error handling + void fail(const std::string &msg) { - /* Load the entire file into memory. This allows us to use - direct pointers to the data arrays in the NIF, instead of - individually allocating and copying each one. - - The NIF data is only stored temporarily in memory, since once - the mesh data is loaded it is siphoned into OGRE and - deleted. For that reason, we might improve this further and - use a shared region/pool based allocation scheme in the - future, especially since only one NIFFile will ever be loaded - at any given time. - */ - inp = StreamPtr(new BufferStream(nif)); - - parse(); + std::string err = "NIFFile Error: " + msg; + err += "\nFile: " + filename; + throw std::runtime_error(err); } - ~NIFFile() + void warn(const std::string &msg) { - for(std::size_t i=0; i= 0 && index < static_cast (records.size())); - Record *res = records[index]; - assert(res != NULL); - return res; - } + /// Open a NIF stream. The name is used for error messages. + NIFFile(const std::string &name) + : filename(name) + { + inp = Ogre::ResourceGroupManager::getSingleton().openResource(name); + parse(); + } - /// Number of records - int numRecords() { return records.size(); } + ~NIFFile() + { + for(std::size_t i=0; iskip(size); } - void skip(size_t size) { inp->getPtr(size); } - - template const X* getPtr() { return (const X*)inp->getPtr(sizeof(X)); } - template X getType() { return *getPtr(); } - unsigned short getShort() { return getType(); } - int getInt() { return getType(); } - float getFloat() { return getType(); } - char getByte() { return getType(); } - - template - Misc::SliceArray getArrayLen(int num) - { return Misc::SliceArray((const X*)inp->getPtr(num*sizeof(X)),num); } - - template - Misc::SliceArray getArray() + char getChar() { return read_byte(); } + short getShort() { return read_le16(); } + unsigned short getUShort() { return read_le16(); } + int getInt() { return read_le32(); } + float getFloat() { return read_le32f(); } + Ogre::Vector2 getVector2() { - int len = getInt(); - return getArrayLen(len); + float a[2]; + for(size_t i = 0;i < 2;i++) + a[i] = getFloat(); + return Ogre::Vector2(a); + } + Ogre::Vector3 getVector3() + { + float a[3]; + for(size_t i = 0;i < 3;i++) + a[i] = getFloat(); + return Ogre::Vector3(a); + } + Ogre::Vector4 getVector4() + { + float a[4]; + for(size_t i = 0;i < 4;i++) + a[i] = getFloat(); + return Ogre::Vector4(a); + } + Ogre::Matrix3 getMatrix3() + { + Ogre::Real a[3][3]; + for(size_t i = 0;i < 3;i++) + { + for(size_t j = 0;j < 3;j++) + a[i][j] = Ogre::Real(getFloat()); + } + return Ogre::Matrix3(a); + } + Ogre::Quaternion getQuaternion() + { + float a[4]; + for(size_t i = 0;i < 4;i++) + a[i] = getFloat(); + return Ogre::Quaternion(a); + } + Transformation getTrafo() + { + Transformation t; + t.pos = getVector3(); + t.rotation = getMatrix3(); + t.scale = getFloat(); + return t; } - Misc::SString getString() { return getArray(); } + std::string getString(size_t length) + { + std::string str; + str.resize(length); + if(inp->read(&str[0], length) != length) + return std::string(); + return str.substr(0, str.find('\0')); + } + std::string getString() + { + size_t size = read_le32(); + return getString(size); + } - const Vector *getVector() { return getPtr(); } - const Matrix *getMatrix() { return getPtr(); } - const Transformation *getTrafo() { return getPtr(); } - const Vector4 *getVector4() { return getPtr(); } - - Misc::FloatArray getFloatLen(int num) - { return getArrayLen(num); } - - // For fixed-size strings where you already know the size - const char *getString(int size) - { return (const char*)inp->getPtr(size); } + void getShorts(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getShort(); + } + void getFloats(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getFloat(); + } + void getVector2s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector2(); + } + void getVector3s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector3(); + } + void getVector4s(std::vector &vec, size_t size) + { + vec.resize(size); + for(size_t i = 0;i < vec.size();i++) + vec[i] = getVector4(); + } }; + +template +struct KeyT { + float mTime; + T mValue; + T mForwardValue; // Only for Quadratic interpolation + T mBackwardValue; // Only for Quadratic interpolation + float mTension; // Only for TBC interpolation + float mBias; // Only for TBC interpolation + float mContinuity; // Only for TBC interpolation +}; +typedef KeyT FloatKey; +typedef KeyT Vector3Key; +typedef KeyT Vector4Key; +typedef KeyT QuaternionKey; + +template +struct KeyListT { + typedef std::vector< KeyT > VecType; + + static const int sLinearInterpolation = 1; + static const int sQuadraticInterpolation = 2; + static const int sTBCInterpolation = 3; + + int mInterpolationType; + VecType mKeys; + + void read(NIFFile *nif, bool force=false) + { + size_t count = nif->getInt(); + if(count == 0 && !force) + return; + + mInterpolationType = nif->getInt(); + mKeys.resize(count); + if(mInterpolationType == sLinearInterpolation) + { + for(size_t i = 0;i < count;i++) + { + KeyT &key = mKeys[i]; + key.mTime = nif->getFloat(); + key.mValue = (nif->*getValue)(); + } + } + else if(mInterpolationType == sQuadraticInterpolation) + { + for(size_t i = 0;i < count;i++) + { + KeyT &key = mKeys[i]; + key.mTime = nif->getFloat(); + key.mValue = (nif->*getValue)(); + key.mForwardValue = (nif->*getValue)(); + key.mBackwardValue = (nif->*getValue)(); + } + } + else if(mInterpolationType == sTBCInterpolation) + { + for(size_t i = 0;i < count;i++) + { + KeyT &key = mKeys[i]; + key.mTime = nif->getFloat(); + key.mValue = (nif->*getValue)(); + key.mTension = nif->getFloat(); + key.mBias = nif->getFloat(); + key.mContinuity = nif->getFloat(); + } + } + else + nif->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + } +}; +typedef KeyListT FloatKeyList; +typedef KeyListT Vector3KeyList; +typedef KeyListT Vector4KeyList; +typedef KeyListT QuaternionKeyList; + } // Namespace #endif diff --git a/components/nif/nif_types.hpp b/components/nif/nif_types.hpp index ee796cc99..a5fb61361 100644 --- a/components/nif/nif_types.hpp +++ b/components/nif/nif_types.hpp @@ -24,59 +24,28 @@ #ifndef _NIF_TYPES_H_ #define _NIF_TYPES_H_ +#include +#include + // Common types used in NIF files namespace Nif { -/* These packing #pragmas aren't really necessary on 32 bit - machines. I haven't tested on 64 bit yet. In any case it doesn't - hurt to include them. We can't allow any compiler-generated padding - in any of these structs, since they are used to interface directly - with raw data from the NIF files. -*/ -#pragma pack(push) -#pragma pack(1) - -struct Vector -{ - float array[3]; -}; - -struct Vector4 -{ - float array[4]; -}; - -struct Matrix -{ - Vector v[3]; -}; - struct Transformation { - Vector pos; - Matrix rotation; + Ogre::Vector3 pos; + Ogre::Matrix3 rotation; float scale; - Vector velocity; - static const Transformation* getIdentity() + static const Transformation& getIdentity() { - static Transformation identity; - static bool iset = false; - if (!iset) - { - identity.scale = 1.0f; - identity.rotation.v[0].array[0] = 1.0f; - identity.rotation.v[1].array[1] = 1.0f; - identity.rotation.v[2].array[2] = 1.0f; - iset = true; - } - - return &identity; + static const Transformation identity = { + Ogre::Vector3::ZERO, Ogre::Matrix3::IDENTITY, 1.0f + }; + return identity; } }; -#pragma pack(pop) } // Namespace #endif diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 080042746..f7d3c6e96 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -24,12 +24,17 @@ #ifndef _NIF_NODE_H_ #define _NIF_NODE_H_ +#include + #include "controlled.hpp" #include "data.hpp" +#include "property.hpp" namespace Nif { +class NiNode; + /** A Node is an object that's part of the main NIF tree. It has parent node (unless it's the root), and transformation (location and rotation) relative to it's parent. @@ -37,191 +42,219 @@ namespace Nif class Node : public Named { public: - // Node flags. Interpretation depends somewhat on the type of node. - int flags; - const Transformation *trafo; - PropertyList props; + // Node flags. Interpretation depends somewhat on the type of node. + int flags; + Transformation trafo; + Ogre::Vector3 velocity; // Unused? Might be a run-time game state + PropertyList props; - // Bounding box info - bool hasBounds; - const Vector *boundPos; - const Matrix *boundRot; - const Vector *boundXYZ; // Box size + // Bounding box info + bool hasBounds; + Ogre::Vector3 boundPos; + Ogre::Matrix3 boundRot; + Ogre::Vector3 boundXYZ; // Box size - void read(NIFFile *nif) - { - Named::read(nif); + void read(NIFFile *nif) + { + Named::read(nif); - flags = nif->getShort(); - trafo = nif->getTrafo(); - props.read(nif); + flags = nif->getUShort(); + trafo = nif->getTrafo(); + velocity = nif->getVector3(); + props.read(nif); - hasBounds = !!nif->getInt(); - if(hasBounds) - { - nif->getInt(); // always 1 - boundPos = nif->getVector(); - boundRot = nif->getMatrix(); - boundXYZ = nif->getVector(); - } + hasBounds = !!nif->getInt(); + if(hasBounds) + { + nif->getInt(); // always 1 + boundPos = nif->getVector3(); + boundRot = nif->getMatrix3(); + boundXYZ = nif->getVector3(); + } - boneTrafo = NULL; - boneIndex = -1; - } + parent = NULL; - // Bone transformation. If set, node is a part of a skeleton. - const NiSkinData::BoneTrafo *boneTrafo; + boneTrafo = NULL; + boneIndex = -1; + } - // Bone weight info, from NiSkinData - const NiSkinData::BoneInfo *boneInfo; + void post(NIFFile *nif) + { + Named::post(nif); + props.post(nif); + } - // Bone index. If -1, this node is either not a bone, or if - // boneTrafo is set it is the root bone in the skeleton. - short boneIndex; + // Parent node, or NULL for the root node. As far as I'm aware, only + // NiNodes (or types derived from NiNodes) can be parents. + NiNode *parent; - void makeRootBone(const NiSkinData::BoneTrafo *tr) - { - boneTrafo = tr; - boneIndex = -1; - } + // Bone transformation. If set, node is a part of a skeleton. + const NiSkinData::BoneTrafo *boneTrafo; - void makeBone(short ind, const NiSkinData::BoneInfo &bi) - { - boneInfo = &bi; - boneTrafo = bi.trafo; - boneIndex = ind; - } -}; + // Bone weight info, from NiSkinData + const NiSkinData::BoneInfo *boneInfo; -struct NiTriShapeCopy -{ - std::string sname; - std::vector boneSequence; - Nif::NiSkinData::BoneTrafoCopy trafo; - //Ogre::Quaternion initialBoneRotation; - //Ogre::Vector3 initialBoneTranslation; - std::vector vertices; - std::vector normals; - std::vector boneinfo; - std::map > vertsToWeights; - Nif::NiMorphData morph; + // Bone index. If -1, this node is either not a bone, or if + // boneTrafo is set it is the root bone in the skeleton. + short boneIndex; + + void makeRootBone(const NiSkinData::BoneTrafo *tr) + { + boneTrafo = tr; + boneIndex = -1; + } + + void makeBone(short ind, const NiSkinData::BoneInfo &bi) + { + boneInfo = &bi; + boneTrafo = &bi.trafo; + boneIndex = ind; + } + + Ogre::Matrix4 getLocalTransform(); + Ogre::Matrix4 getWorldTransform(); }; struct NiNode : Node { - NodeList children; - NodeList effects; + NodeList children; + NodeList effects; - /* Known NiNode flags: + /* Known NiNode flags: + 0x01 hidden + 0x02 use mesh for collision + 0x04 use bounding box for collision (?) + 0x08 unknown, but common + 0x20, 0x40, 0x80 unknown + */ - 0x01 hidden - 0x02 use mesh for collision - 0x04 use bounding box for collision (?) - 0x08 unknown, but common - 0x20, 0x40, 0x80 unknown - */ + void read(NIFFile *nif) + { + Node::read(nif); + children.read(nif); + effects.read(nif); + } - void read(NIFFile *nif) - { - Node::read(nif); - children.read(nif); - effects.read(nif); - } + void post(NIFFile *nif) + { + Node::post(nif); + children.post(nif); + effects.post(nif); + + for(size_t i = 0;i < children.length();i++) + { + // Why would a unique list of children contain empty refs? + if(!children[i].empty()) + children[i]->parent = this; + } + } }; struct NiTriShape : Node { - /* Possible flags: - 0x40 - mesh has no vertex normals ? + /* Possible flags: + 0x40 - mesh has no vertex normals ? - Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have - been observed so far. - */ + Only flags included in 0x47 (ie. 0x01, 0x02, 0x04 and 0x40) have + been observed so far. + */ - NiTriShapeDataPtr data; - NiSkinInstancePtr skin; + NiTriShapeDataPtr data; + NiSkinInstancePtr skin; - void read(NIFFile *nif) - { - Node::read(nif); - data.read(nif); - skin.read(nif); - } + void read(NIFFile *nif) + { + Node::read(nif); + data.read(nif); + skin.read(nif); + } - NiTriShapeCopy clone(){ - NiTriShapeCopy copy; - copy.sname = name.toString(); - float *ptr = (float*)data->vertices.ptr; - float *ptrNormals = (float*)data->normals.ptr; - int numVerts = data->vertices.length / 3; - for(int i = 0; i < numVerts; i++) - { - float *current = (float*) (ptr + i * 3); - copy.vertices.push_back(Ogre::Vector3(*current, *(current + 1), *(current + 2))); - - if(ptrNormals){ - float *currentNormals = (float*) (ptrNormals + i * 3); - copy.normals.push_back(Ogre::Vector3(*currentNormals, *(currentNormals + 1), *(currentNormals + 2))); - } - } - - - return copy; - } + void post(NIFFile *nif) + { + Node::post(nif); + data.post(nif); + skin.post(nif); + } }; struct NiCamera : Node { - struct Camera - { - // Camera frustrum - float left, right, top, bottom, nearDist, farDist; + struct Camera + { + // Camera frustrum + float left, right, top, bottom, nearDist, farDist; - // Viewport - float vleft, vright, vtop, vbottom; + // Viewport + float vleft, vright, vtop, vbottom; - // Level of detail modifier - float LOD; - }; + // Level of detail modifier + float LOD; - const Camera *cam; + void read(NIFFile *nif) + { + left = nif->getFloat(); + right = nif->getFloat(); + top = nif->getFloat(); + bottom = nif->getFloat(); + nearDist = nif->getFloat(); + farDist = nif->getFloat(); - void read(NIFFile *nif) - { - Node::read(nif); + vleft = nif->getFloat(); + vright = nif->getFloat(); + vtop = nif->getFloat(); + vbottom = nif->getFloat(); - nif->getPtr(); + LOD = nif->getFloat(); + } + }; + Camera cam; - nif->getInt(); // -1 - nif->getInt(); // 0 - } + void read(NIFFile *nif) + { + Node::read(nif); + + cam.read(nif); + + nif->getInt(); // -1 + nif->getInt(); // 0 + } }; struct NiAutoNormalParticles : Node { - NiAutoNormalParticlesDataPtr data; + NiAutoNormalParticlesDataPtr data; - void read(NIFFile *nif) - { - Node::read(nif); - data.read(nif); - nif->getInt(); // -1 - } + void read(NIFFile *nif) + { + Node::read(nif); + data.read(nif); + nif->getInt(); // -1 + } + + void post(NIFFile *nif) + { + Node::post(nif); + data.post(nif); + } }; struct NiRotatingParticles : Node { - NiRotatingParticlesDataPtr data; + NiRotatingParticlesDataPtr data; - void read(NIFFile *nif) - { - Node::read(nif); - data.read(nif); - nif->getInt(); // -1 - } + void read(NIFFile *nif) + { + Node::read(nif); + data.read(nif); + nif->getInt(); // -1 + } + + void post(NIFFile *nif) + { + Node::post(nif); + data.post(nif); + } }; - - } // Namespace #endif diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 1a16854af..b24e49b47 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -32,104 +32,116 @@ namespace Nif class Property : public Named { public: - // The meaning of these depends on the actual property type. - int flags; + // The meaning of these depends on the actual property type. + int flags; - void read(NIFFile *nif) - { - Named::read(nif); - flags = nif->getShort(); - } + void read(NIFFile *nif) + { + Named::read(nif); + flags = nif->getUShort(); + } }; class NiTexturingProperty : public Property { public: - // A sub-texture - struct Texture - { - /* Clamp mode - 0 - clampS clampT - 1 - clampS wrapT - 2 - wrapS clampT - 3 - wrapS wrapT - */ + // A sub-texture + struct Texture + { + /* Clamp mode + 0 - clampS clampT + 1 - clampS wrapT + 2 - wrapS clampT + 3 - wrapS wrapT + */ - /* Filter: - 0 - nearest - 1 - bilinear - 2 - trilinear - 3, 4, 5 - who knows - */ - bool inUse; - NiSourceTexturePtr texture; + /* Filter: + 0 - nearest + 1 - bilinear + 2 - trilinear + 3, 4, 5 - who knows + */ + bool inUse; + NiSourceTexturePtr texture; - int clamp, set, filter; - short unknown2; + int clamp, set, filter; + short unknown2; + + void read(NIFFile *nif) + { + inUse = !!nif->getInt(); + if(!inUse) return; + + texture.read(nif); + clamp = nif->getInt(); + filter = nif->getInt(); + set = nif->getInt(); + + // I have no idea, but I think these are actually two + // PS2-specific shorts (ps2L and ps2K), followed by an unknown + // short. + nif->skip(6); + } + + void post(NIFFile *nif) + { + texture.post(nif); + } + }; + + /* Apply mode: + 0 - replace + 1 - decal + 2 - modulate + 3 - hilight // These two are for PS2 only? + 4 - hilight2 + */ + int apply; + + /* + * The textures in this list are as follows: + * + * 0 - Base texture + * 1 - Dark texture + * 2 - Detail texture + * 3 - Gloss texture (never used?) + * 4 - Glow texture + * 5 - Bump map texture + * 6 - Decal texture + */ + Texture textures[7]; void read(NIFFile *nif) { - inUse = !!nif->getInt(); - if(!inUse) return; + Property::read(nif); + apply = nif->getInt(); - texture.read(nif); - clamp = nif->getInt(); - filter = nif->getInt(); - set = nif->getInt(); + // Unknown, always 7. Probably the number of textures to read + // below + nif->getInt(); - // I have no idea, but I think these are actually two - // PS2-specific shorts (ps2L and ps2K), followed by an unknown - // short. - nif->skip(6); + textures[0].read(nif); // Base + textures[1].read(nif); // Dark + textures[2].read(nif); // Detail + textures[3].read(nif); // Gloss (never present) + textures[4].read(nif); // Glow + textures[5].read(nif); // Bump map + if(textures[5].inUse) + { + // Ignore these at the moment + /*float lumaScale =*/ nif->getFloat(); + /*float lumaOffset =*/ nif->getFloat(); + /*const Vector4 *lumaMatrix =*/ nif->getVector4(); + } + textures[6].read(nif); // Decal } - }; - /* Apply mode: - 0 - replace - 1 - decal - 2 - modulate - 3 - hilight // These two are for PS2 only? - 4 - hilight2 - */ - int apply; - - /* - * The textures in this list are as follows: - * - * 0 - Base texture - * 1 - Dark texture - * 2 - Detail texture - * 3 - Gloss texture (never used?) - * 4 - Glow texture - * 5 - Bump map texture - * 6 - Decal texture - */ - Texture textures[7]; - - void read(NIFFile *nif) - { - Property::read(nif); - apply = nif->getInt(); - - // Unknown, always 7. Probably the number of textures to read - // below - nif->getInt(); - - textures[0].read(nif); // Base - textures[1].read(nif); // Dark - textures[2].read(nif); // Detail - textures[3].read(nif); // Gloss (never present) - textures[4].read(nif); // Glow - textures[5].read(nif); // Bump map - if(textures[5].inUse) - { - // Ignore these at the moment - /*float lumaScale =*/ nif->getFloat(); - /*float lumaOffset =*/ nif->getFloat(); - /*const Vector4 *lumaMatrix =*/ nif->getVector4(); - } - textures[6].read(nif); // Decal - } + void post(NIFFile *nif) + { + Property::post(nif); + for(int i = 0;i < 7;i++) + textures[i].post(nif); + } }; // These contain no other data than the 'flags' field in Property @@ -140,88 +152,109 @@ typedef Property NiSpecularProperty; typedef Property NiWireframeProperty; // The rest are all struct-based -template +template struct StructPropT : Property { - const Struct* data; + T data; - void read(NIFFile *nif) - { - Property::read(nif); - data = nif->getPtr(); - } + void read(NIFFile *nif) + { + Property::read(nif); + data.read(nif); + } }; struct S_MaterialProperty { - // The vector components are R,G,B - Vector ambient, diffuse, specular, emissive; - float glossiness, alpha; + // The vector components are R,G,B + Ogre::Vector3 ambient, diffuse, specular, emissive; + float glossiness, alpha; + + void read(NIFFile *nif) + { + ambient = nif->getVector3(); + diffuse = nif->getVector3(); + specular = nif->getVector3(); + emissive = nif->getVector3(); + glossiness = nif->getFloat(); + alpha = nif->getFloat(); + } }; struct S_VertexColorProperty { - /* Vertex mode: - 0 - source ignore - 1 - source emmisive - 2 - source amb diff + /* Vertex mode: + 0 - source ignore + 1 - source emmisive + 2 - source amb diff - Lighting mode - 0 - lighting emmisive - 1 - lighting emmisive ambient/diffuse - */ - int vertmode, lightmode; + Lighting mode + 0 - lighting emmisive + 1 - lighting emmisive ambient/diffuse + */ + int vertmode, lightmode; + + void read(NIFFile *nif) + { + vertmode = nif->getInt(); + lightmode = nif->getInt(); + } }; struct S_AlphaProperty { - /* - In NiAlphaProperty, the flags have the following meaning: + /* + In NiAlphaProperty, the flags have the following meaning: - Bit 0 : alpha blending enable - Bits 1-4 : source blend mode - Bits 5-8 : destination blend mode - Bit 9 : alpha test enable - Bit 10-12 : alpha test mode - Bit 13 : no sorter flag ( disables triangle sorting ) + Bit 0 : alpha blending enable + Bits 1-4 : source blend mode + Bits 5-8 : destination blend mode + Bit 9 : alpha test enable + Bit 10-12 : alpha test mode + Bit 13 : no sorter flag ( disables triangle sorting ) - blend modes (glBlendFunc): - 0000 GL_ONE - 0001 GL_ZERO - 0010 GL_SRC_COLOR - 0011 GL_ONE_MINUS_SRC_COLOR - 0100 GL_DST_COLOR - 0101 GL_ONE_MINUS_DST_COLOR - 0110 GL_SRC_ALPHA - 0111 GL_ONE_MINUS_SRC_ALPHA - 1000 GL_DST_ALPHA - 1001 GL_ONE_MINUS_DST_ALPHA - 1010 GL_SRC_ALPHA_SATURATE + blend modes (glBlendFunc): + 0000 GL_ONE + 0001 GL_ZERO + 0010 GL_SRC_COLOR + 0011 GL_ONE_MINUS_SRC_COLOR + 0100 GL_DST_COLOR + 0101 GL_ONE_MINUS_DST_COLOR + 0110 GL_SRC_ALPHA + 0111 GL_ONE_MINUS_SRC_ALPHA + 1000 GL_DST_ALPHA + 1001 GL_ONE_MINUS_DST_ALPHA + 1010 GL_SRC_ALPHA_SATURATE - test modes (glAlphaFunc): - 000 GL_ALWAYS - 001 GL_LESS - 010 GL_EQUAL - 011 GL_LEQUAL - 100 GL_GREATER - 101 GL_NOTEQUAL - 110 GL_GEQUAL - 111 GL_NEVER + test modes (glAlphaFunc): + 000 GL_ALWAYS + 001 GL_LESS + 010 GL_EQUAL + 011 GL_LEQUAL + 100 GL_GREATER + 101 GL_NOTEQUAL + 110 GL_GEQUAL + 111 GL_NEVER - Taken from: - http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html + Taken from: + http://niftools.sourceforge.net/doc/nif/NiAlphaProperty.html - Right now we only use standard alpha blending (see the Ogre code - that sets it up) and it appears that this is the only blending - used in the original game. Bloodmoon (along with several mods) do - however use other settings, such as discarding pixel values with - alpha < 1.0. This is faster because we don't have to mess with the - depth stuff like we did for blending. And OGRE has settings for - this too. - */ + Right now we only use standard alpha blending (see the Ogre code + that sets it up) and it appears that this is the only blending + used in the original game. Bloodmoon (along with several mods) do + however use other settings, such as discarding pixel values with + alpha < 1.0. This is faster because we don't have to mess with the + depth stuff like we did for blending. And OGRE has settings for + this too. + */ - // Tested against when certain flags are set (see above.) - unsigned char threshold; + // Tested against when certain flags are set (see above.) + unsigned char threshold; + + void read(NIFFile *nif) + { + threshold = nif->getChar(); + } }; typedef StructPropT NiAlphaProperty; diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 40f91f84f..5c4141fa9 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -24,7 +24,7 @@ #ifndef _NIF_RECORD_H_ #define _NIF_RECORD_H_ -#include +#include namespace Nif { @@ -88,26 +88,25 @@ enum RecordType /// Base class for all records struct Record { - // Record type and type name - int recType; - Misc::SString recName; + // Record type and type name + int recType; + std::string recName; - Record() : recType(RC_MISSING) {} + Record() : recType(RC_MISSING) {} - /// Parses the record from file - virtual void read(NIFFile *nif) = 0; + /// Parses the record from file + virtual void read(NIFFile *nif) = 0; - /// Does post-processing, after the entire tree is loaded - virtual void post(NIFFile *nif) {} + /// Does post-processing, after the entire tree is loaded + virtual void post(NIFFile *nif) {} virtual ~Record() {} - /* - Use these later if you want custom allocation of all NIF objects - - static void* operator new(size_t size); - static void operator delete(void *p); - */ + /* + Use these later if you want custom allocation of all NIF objects + static void* operator new(size_t size); + static void operator delete(void *p); + */ }; } // Namespace diff --git a/components/nif/record_ptr.hpp b/components/nif/record_ptr.hpp index c5618941e..ef5bb1dee 100644 --- a/components/nif/record_ptr.hpp +++ b/components/nif/record_ptr.hpp @@ -37,61 +37,55 @@ namespace Nif template class RecordPtrT { - int index; - X* ptr; - NIFFile *nif; + union { + intptr_t index; + X* ptr; + }; - public: +public: + RecordPtrT() : index(-2) {} - RecordPtrT() : index(-2), ptr(NULL) {} + /// Read the index from the nif + void read(NIFFile *nif) + { + // Can only read the index once + assert(index == -2); - /// Read the index from the nif - void read(NIFFile *_nif) - { - // Can only read the index once - assert(index == -2); + // Store the index for later + index = nif->getInt(); + assert(index >= -1); + } - // Store the NIFFile pointer for later - nif = _nif; + /// Resolve index to pointer + void post(NIFFile *nif) + { + if(index < 0) + ptr = NULL; + else + { + Record *r = nif->getRecord(index); + // And cast it + ptr = dynamic_cast(r); + assert(ptr != NULL); + } + } - // And the index, of course - index = nif->getInt(); - } - - /** Set the pointer explicitly. May be used when you are pointing to - records in another file, eg. when you have a .nif / .kf pair. - */ - void set(X *p) - { - ptr = p; - index = -1; - } - - /// Look up the actual object from the index - X* getPtr() - { - // Have we found the pointer already? - if(ptr == NULL) - { - // Get the record - assert(index >= 0); - Record *r = nif->getRecord(index); - - // And cast it - ptr = dynamic_cast(r); + /// Look up the actual object from the index + X* getPtr() const + { assert(ptr != NULL); - } - return ptr; - } + return ptr; + } + X& get() const + { return *getPtr(); } - /// Syntactic sugar - X* operator->() { return getPtr(); } - X& get() { return *getPtr(); } + /// Syntactic sugar + X* operator->() const + { return getPtr(); } - /// Pointers are allowed to be empty - bool empty() { return index == -1 && ptr == NULL; } - - int getIndex() { return index; } + /// Pointers are allowed to be empty + bool empty() const + { return ptr == NULL; } }; /** A list of references to other records. These are read as a list, @@ -101,40 +95,30 @@ class RecordPtrT template class RecordListT { - typedef RecordPtrT Ptr; - std::vector list; + typedef RecordPtrT Ptr; + std::vector list; - public: - - void read(NIFFile *nif) - { - int len = nif->getInt(); - list.resize(len); - - assert(len >= 0 && len < 1000); - for(int i=0;i= 0 && index < static_cast (list.size())); - return list[index].get(); + int len = nif->getInt(); + list.resize(len); + + for(size_t i=0;i < list.size();i++) + list[i].read(nif); } - bool has(int index) - { - assert(index >= 0 && index < static_cast (list.size())); - return !list[index].empty(); - } - - int getIndex(int index) + void post(NIFFile *nif) { - if(has(index)) return list[index].getIndex(); - else return -1; + for(size_t i=0;i < list.size();i++) + list[i].post(nif); } - int length() { return list.size(); } + const Ptr& operator[](size_t index) const + { return list.at(index); } + + size_t length() const + { return list.size(); } }; diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 30cb4562d..071f03630 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -1,4 +1,4 @@ -/* + /* OpenMW - The completely unofficial reimplementation of Morrowind Copyright (C) 2008-2010 Nicolay Korslund Email: < korslund@gmail.com > @@ -23,9 +23,8 @@ http://www.gnu.org/licenses/ . #include "bullet_nif_loader.hpp" #include -#include +#include -#include #include "../nif/nif_file.hpp" #include "../nif/node.hpp" #include "../nif/data.hpp" @@ -44,32 +43,15 @@ http://www.gnu.org/licenses/ . typedef unsigned char ubyte; -using namespace std; -using namespace Ogre; -using namespace Nif; -using namespace Mangle::VFS; - using namespace NifBullet; + ManualBulletShapeLoader::~ManualBulletShapeLoader() { - delete vfs; } -Ogre::Matrix3 ManualBulletShapeLoader::getMatrix(Nif::Transformation* tr) -{ - Ogre::Matrix3 rot(tr->rotation.v[0].array[0],tr->rotation.v[0].array[1],tr->rotation.v[0].array[2], - tr->rotation.v[1].array[0],tr->rotation.v[1].array[1],tr->rotation.v[1].array[2], - tr->rotation.v[2].array[0],tr->rotation.v[2].array[1],tr->rotation.v[2].array[2]); - return rot; -} -Ogre::Vector3 ManualBulletShapeLoader::getVector(Nif::Transformation* tr) -{ - Ogre::Vector3 vect3(tr->pos.array[0],tr->pos.array[1],tr->pos.array[2]); - return vect3; -} -btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 m) +btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 &m) { Ogre::Quaternion oquat(m); btQuaternion quat; @@ -80,10 +62,9 @@ btQuaternion ManualBulletShapeLoader::getbtQuat(Ogre::Matrix3 m) return quat; } -btVector3 ManualBulletShapeLoader::getbtVector(Nif::Vector v) +btVector3 ManualBulletShapeLoader::getbtVector(Ogre::Vector3 &v) { - btVector3 a(v.array[0],v.array[1],v.array[2]); - return a; + return btVector3(v[0], v[1], v[2]); } void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) @@ -94,20 +75,11 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) mTriMesh = new btTriangleMesh(); - if (!vfs) vfs = new OgreVFS(resourceGroup); - - if (!vfs->isFile(resourceName)) - { - warn("File not found."); - return; - } - // Load the NIF. TODO: Wrap this in a try-catch block once we're out // of the early stages of development. Right now we WANT to catch // every error as early and intrusively as possible, as it's most // likely a sign of incomplete code rather than faulty input. - Nif::NIFFile nif(vfs->open(resourceName), resourceName); - + Nif::NIFFile nif(resourceName.substr(0, resourceName.length()-7)); if (nif.numRecords() < 1) { warn("Found no records in NIF."); @@ -120,26 +92,25 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) assert(r != NULL); Nif::Node *node = dynamic_cast(r); - if (node == NULL) { warn("First record in file was not a node, but a " + - r->recName.toString() + ". Skipping file."); + r->recName + ". Skipping file."); return; } bool hasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(node,0,Ogre::Matrix3::IDENTITY,Ogre::Vector3::ZERO,1,hasCollisionNode,false,false); + handleNode(node,0,NULL,hasCollisionNode,false,false); //if collide = false, then it does a second pass which create a shape for raycasting. if(cShape->collide == false) { - handleNode(node,0,Ogre::Matrix3::IDENTITY,Ogre::Vector3::ZERO,1,hasCollisionNode,false,true); + handleNode(node,0,NULL,hasCollisionNode,false,true); } - cShape->collide = hasCollisionNode&&cShape->collide; + //cShape->collide = hasCollisionNode&&cShape->collide; struct TriangleMeshShape : public btBvhTriangleMeshShape { @@ -167,9 +138,9 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node) int n = list.length(); for (int i=0; iflags; @@ -221,18 +193,25 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, } } - //transfo of parents node + curent node - Ogre::Matrix3 finalRot; - Ogre::Vector3 finalPos; - float finalScale; - Nif::Transformation &final = *((Nif::Transformation*)node->trafo); - Ogre::Vector3 nodePos = getVector(&final); - Ogre::Matrix3 nodeRot = getMatrix(&final); + if (trafo) + { - finalPos = nodePos + parentPos; - finalRot = parentRot*nodeRot; - finalScale = final.scale*parentScale; + // Get a non-const reference to the node's data, since we're + // overwriting it. TODO: Is this necessary? + Nif::Transformation &final = node->trafo; + + // For both position and rotation we have that: + // final_vector = old_vector + old_rotation*new_vector*old_scale + final.pos = trafo->pos + trafo->rotation*final.pos*trafo->scale; + + // Merge the rotations together + final.rotation = trafo->rotation * final.rotation; + + // Scale + final.scale *= trafo->scale; + + } // For NiNodes, loop through children @@ -242,16 +221,16 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, int n = list.length(); for (int i=0; itrafo,hasCollisionNode,isCollisionNode,raycastingOnly); } } } - else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) + else if (node->recType == Nif::RC_NiTriShape && (isCollisionNode || !hasCollisionNode)) { cShape->collide = true; - handleNiTriShape(dynamic_cast(node), flags,finalRot,finalPos,parentScale,raycastingOnly); + handleNiTriShape(dynamic_cast(node), flags,node->trafo.rotation,node->trafo.pos,node->trafo.scale,raycastingOnly); } else if(node->recType == Nif::RC_RootCollisionNode) { @@ -259,8 +238,8 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, int n = list.length(); for (int i=0; itrafo, hasCollisionNode,true,raycastingOnly); } } } @@ -292,17 +271,16 @@ void ManualBulletShapeLoader::handleNiTriShape(Nif::NiTriShape *shape, int flags Nif::NiTriShapeData *data = shape->data.getPtr(); - float* vertices = (float*)data->vertices.ptr; - unsigned short* triangles = (unsigned short*)data->triangles.ptr; - - for(unsigned int i=0; i < data->triangles.length; i = i+3) + const std::vector &vertices = data->vertices; + const Ogre::Matrix3 &rot = shape->trafo.rotation; + const Ogre::Vector3 &pos = shape->trafo.pos; + float scale = shape->trafo.scale * parentScale; + short* triangles = &data->triangles[0]; + for(size_t i = 0;i < data->triangles.size();i+=3) { - Ogre::Vector3 b1(vertices[triangles[i+0]*3]*parentScale,vertices[triangles[i+0]*3+1]*parentScale,vertices[triangles[i+0]*3+2]*parentScale); - Ogre::Vector3 b2(vertices[triangles[i+1]*3]*parentScale,vertices[triangles[i+1]*3+1]*parentScale,vertices[triangles[i+1]*3+2]*parentScale); - Ogre::Vector3 b3(vertices[triangles[i+2]*3]*parentScale,vertices[triangles[i+2]*3+1]*parentScale,vertices[triangles[i+2]*3+2]*parentScale); - b1 = parentRot * b1 + parentPos; - b2 = parentRot * b2 + parentPos; - b3 = parentRot * b3 + parentPos; + Ogre::Vector3 b1 = pos + rot*vertices[triangles[i+0]]*scale; + Ogre::Vector3 b2 = pos + rot*vertices[triangles[i+1]]*scale; + Ogre::Vector3 b3 = pos + rot*vertices[triangles[i+2]]*scale; mTriMesh->addTriangle(btVector3(b1.x,b1.y,b1.z),btVector3(b2.x,b2.y,b2.z),btVector3(b3.x,b3.y,b3.z)); } } diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index ed3aceac4..88e1ab189 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -25,37 +25,21 @@ #define _BULLET_NIF_LOADER_H_ #include -#include +#include #include #include #include #include -#include #include "openengine/bullet/BulletShapeLoader.h" -#include -#include // For warning messages #include -// float infinity -#include - namespace Nif { class Node; class Transformation; class NiTriShape; - class Vector; - class Matrix; -} - -namespace Mangle -{ - namespace VFS - { - class OgreVFS; - } } namespace NifBullet @@ -68,7 +52,7 @@ class ManualBulletShapeLoader : public BulletShapeLoader { public: - ManualBulletShapeLoader():resourceGroup("General"){vfs = 0;} + ManualBulletShapeLoader():resourceGroup("General"){} virtual ~ManualBulletShapeLoader(); void warn(std::string msg) @@ -95,22 +79,18 @@ public: void load(const std::string &name,const std::string &group); private: - Ogre::Matrix3 getMatrix(Nif::Transformation* tr); + btQuaternion getbtQuat(Ogre::Matrix3 &m); - Ogre::Vector3 getVector(Nif::Transformation* tr); - - btQuaternion getbtQuat(Ogre::Matrix3 m); - - btVector3 getbtVector(Nif::Vector v); + btVector3 getbtVector(Ogre::Vector3 &v); /** *Parse a node. */ void handleNode(Nif::Node *node, int flags, - Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScale,bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); + const Nif::Transformation *trafo, bool hasCollisionNode,bool isCollisionNode,bool raycastingOnly); /** - *Helpler function + *Helper function */ bool hasRootCollisionNode(Nif::Node* node); @@ -119,8 +99,6 @@ private: */ void handleNiTriShape(Nif::NiTriShape *shape, int flags,Ogre::Matrix3 parentRot,Ogre::Vector3 parentPos,float parentScales,bool raycastingOnly); - Mangle::VFS::OgreVFS *vfs; - std::string resourceName; std::string resourceGroup; diff --git a/components/nifogre/ogre_nif_loader.cpp b/components/nifogre/ogre_nif_loader.cpp index 8882bebcd..74b8ea8f3 100644 --- a/components/nifogre/ogre_nif_loader.cpp +++ b/components/nifogre/ogre_nif_loader.cpp @@ -25,55 +25,33 @@ #include "ogre_nif_loader.hpp" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + #include #include typedef unsigned char ubyte; using namespace std; -using namespace Ogre; using namespace Nif; -using namespace Mangle::VFS; -using namespace Misc; using namespace NifOgre; -NIFLoader& NIFLoader::getSingleton() -{ - static NIFLoader instance; - return instance; -} - -NIFLoader* NIFLoader::getSingletonPtr() -{ - return &getSingleton(); -} - -void NIFLoader::warn(string msg) -{ - std::cerr << "NIFLoader: Warn:" << msg << "\n"; -} - -void NIFLoader::fail(string msg) -{ - std::cerr << "NIFLoader: Fail: "<< msg << std::endl; - assert(1); -} - -Vector3 NIFLoader::convertVector3(const Nif::Vector& vec) -{ - return Ogre::Vector3(vec.array); -} - -Quaternion NIFLoader::convertRotation(const Nif::Matrix& rot) -{ - Real matrix[3][3]; - - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - matrix[i][j] = rot.v[i].array[j]; - - return Quaternion(Matrix3(matrix)); -} // Helper class that computes the bounding box and of a mesh class BoundsFinder @@ -159,6 +137,264 @@ public: } }; + +class NIFSkeletonLoader : public Ogre::ManualResourceLoader { + +static void warn(const std::string &msg) +{ + std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; +} + +static void fail(const std::string &msg) +{ + std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; + abort(); +} + + +void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, std::vector &ctrls, Ogre::Bone *parent=NULL) +{ + Ogre::Bone *bone; + if(!skel->hasBone(node->name)) + bone = skel->createBone(node->name); + else + bone = skel->createBone(); + if(parent) parent->addChild(bone); + + bone->setOrientation(node->trafo.rotation); + bone->setPosition(node->trafo.pos); + bone->setScale(Ogre::Vector3(node->trafo.scale)); + bone->setBindingPose(); + bone->setInitialState(); + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiKeyframeController) + ctrls.push_back(static_cast(ctrl.getPtr())); + ctrl = ctrl->next; + } + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + buildBones(skel, children[i].getPtr(), ctrls, bone); + } + } +} + + +/* Comparitor to help sort Key<> vectors */ +template +struct KeyTimeSort +{ + bool operator()(const Nif::KeyT &lhs, const Nif::KeyT &rhs) const + { return lhs.mTime < rhs.mTime; } +}; + + +typedef std::map LoaderMap; +static LoaderMap sLoaders; + +public: +void loadResource(Ogre::Resource *resource) +{ + Ogre::Skeleton *skel = dynamic_cast(resource); + OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); + + Nif::NIFFile nif(skel->getName()); + const Nif::Node *node = dynamic_cast(nif.getRecord(0)); + + std::vector ctrls; + buildBones(skel, node, ctrls); + + std::vector targets; + // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file + if(ctrls.size() == 0) // No animations? Then we're done. + return; + + float maxtime = 0.0f; + for(size_t i = 0;i < ctrls.size();i++) + { + Nif::NiKeyframeController *ctrl = ctrls[i]; + maxtime = std::max(maxtime, ctrl->timeStop); + Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); + if(target != NULL) + targets.push_back(target->name); + } + + if(targets.size() != ctrls.size()) + { + warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ + Ogre::StringConverter::toString(ctrls.size())+" controllers)"); + return; + } + + Ogre::Animation *anim = skel->createAnimation(skel->getName(), maxtime); + /* HACK: Pre-create the node tracks by matching the track IDs with the + * bone IDs. Otherwise, Ogre animates the wrong bones. */ + size_t bonecount = skel->getNumBones(); + for(size_t i = 0;i < bonecount;i++) + anim->createNodeTrack(i, skel->getBone(i)); + + for(size_t i = 0;i < ctrls.size();i++) + { + Nif::NiKeyframeController *kfc = ctrls[i]; + Nif::NiKeyframeData *kf = kfc->data.getPtr(); + + /* Get the keyframes and make sure they're sorted first to last */ + QuaternionKeyList quatkeys = kf->mRotations; + Vector3KeyList trankeys = kf->mTranslations; + FloatKeyList scalekeys = kf->mScales; + std::sort(quatkeys.mKeys.begin(), quatkeys.mKeys.end(), KeyTimeSort()); + std::sort(trankeys.mKeys.begin(), trankeys.mKeys.end(), KeyTimeSort()); + std::sort(scalekeys.mKeys.begin(), scalekeys.mKeys.end(), KeyTimeSort()); + + QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + + Ogre::Bone *bone = skel->getBone(targets[i]); + const Ogre::Quaternion startquat = bone->getInitialOrientation(); + const Ogre::Vector3 starttrans = bone->getInitialPosition(); + const Ogre::Vector3 startscale = bone->getInitialScale(); + Ogre::NodeAnimationTrack *nodetrack = anim->getNodeTrack(bone->getHandle()); + + Ogre::Quaternion lastquat, curquat; + Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); + Ogre::Vector3 lastscale(1.0f), curscale(1.0f); + if(quatiter != quatkeys.mKeys.end()) + lastquat = curquat = startquat.Inverse() * quatiter->mValue; + if(traniter != trankeys.mKeys.end()) + lasttrans = curtrans = traniter->mValue - starttrans; + if(scaleiter != scalekeys.mKeys.end()) + lastscale = curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + bool didlast = false; + while(!didlast) + { + float curtime = kfc->timeStop; + if(quatiter != quatkeys.mKeys.end()) + curtime = std::min(curtime, quatiter->mTime); + if(traniter != trankeys.mKeys.end()) + curtime = std::min(curtime, traniter->mTime); + if(scaleiter != scalekeys.mKeys.end()) + curtime = std::min(curtime, scaleiter->mTime); + + curtime = std::max(curtime, kfc->timeStart); + if(curtime >= kfc->timeStop) + { + didlast = true; + curtime = kfc->timeStop; + } + + // Get the latest quaternion, translation, and scale for the + // current time + while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) + { + lastquat = curquat; + curquat = startquat.Inverse() * quatiter->mValue; + quatiter++; + } + while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) + { + lasttrans = curtrans; + curtrans = traniter->mValue - starttrans; + traniter++; + } + while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) + { + lastscale = curscale; + curscale = Ogre::Vector3(scaleiter->mValue) / startscale; + scaleiter++; + } + + Ogre::TransformKeyFrame *kframe; + kframe = nodetrack->createNodeKeyFrame(curtime); + if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin() || (quatiter-1)->mTime == curtime) + kframe->setRotation(curquat); + else + { + QuaternionKeyList::VecType::const_iterator last = quatiter-1; + float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); + kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); + } + if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin() || (traniter-1)->mTime == curtime) + kframe->setTranslate(curtrans); + else + { + Vector3KeyList::VecType::const_iterator last = traniter-1; + float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); + kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); + } + if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin() || (scaleiter-1)->mTime == curtime) + kframe->setScale(curscale); + else + { + FloatKeyList::VecType::const_iterator last = scaleiter-1; + float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); + kframe->setScale(lastscale + ((curscale-lastscale)*diff)); + } + } + } + anim->optimise(); +} + +bool createSkeleton(const std::string &name, const std::string &group, TextKeyMap *textkeys, const Nif::Node *node) +{ + if(textkeys) + { + Nif::ExtraPtr e = node->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiTextKeyExtraData) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + for(size_t i = 0;i < tk->list.size();i++) + (*textkeys)[tk->list[i].time] = tk->list[i].text; + } + e = e->extra; + } + } + + if(node->boneTrafo != NULL) + { + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + + Ogre::SkeletonPtr skel = skelMgr.getByName(name); + if(skel.isNull()) + { + NIFSkeletonLoader *loader = &sLoaders[name]; + skel = skelMgr.create(name, group, true, loader); + } + + if(!textkeys || textkeys->size() > 0) + return true; + } + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + { + if(createSkeleton(name, group, textkeys, children[i].getPtr())) + return true; + } + } + } + return false; +} + +}; +NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; + + // Conversion of blend / test mode from NIF -> OGRE. // Not in use yet, so let's comment it out. /* @@ -203,1254 +439,710 @@ static CompareFunction getTestMode(int mode) } */ -void NIFLoader::setOutputAnimFiles(bool output){ - mOutputAnimFiles = output; -} -void NIFLoader::setVerbosePath(std::string path){ - verbosePath = path; -} -void NIFLoader::createMaterial(const String &name, - const Vector &ambient, - const Vector &diffuse, - const Vector &specular, - const Vector &emissive, - float glossiness, float alpha, - int alphaFlags, float alphaTest, - const String &texName) + +class NIFMaterialLoader { + +static std::map MaterialMap; + +static void warn(const std::string &msg) { - MaterialPtr material = MaterialManager::getSingleton().create(name, resourceGroup); + std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; +} + +static void fail(const std::string &msg) +{ + std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + abort(); +} - //Hardware Skinning code, textures may be the wrong color if enabled +public: +static Ogre::String getMaterial(const NiTriShape *shape, const Ogre::String &name, const Ogre::String &group) +{ + Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); + Ogre::MaterialPtr material = matMgr.getByName(name); + if(!material.isNull()) + return name; - /* if(!mSkel.isNull()){ - material->removeAllTechniques(); + Ogre::Vector3 ambient(1.0f); + Ogre::Vector3 diffuse(1.0f); + Ogre::Vector3 specular(0.0f); + Ogre::Vector3 emissive(0.0f); + float glossiness = 0.0f; + float alpha = 1.0f; + int alphaFlags = -1; + ubyte alphaTest = 0; + Ogre::String texName; - Ogre::Technique* tech = material->createTechnique(); - //tech->setSchemeName("blahblah"); - Pass* pass = tech->createPass(); - pass->setVertexProgram("Ogre/BasicVertexPrograms/AmbientOneTexture");*/ - + bool vertexColour = (shape->data->colors.size() != 0); - // This assigns the texture to this material. If the texture name is - // a file name, and this file exists (in a resource directory), it - // will automatically be loaded when needed. If not (such as for - // internal NIF textures that we might support later), we should - // already have inserted a manual loader for the texture. + // These are set below if present + const NiTexturingProperty *t = NULL; + const NiMaterialProperty *m = NULL; + const NiAlphaProperty *a = NULL; - - if (!texName.empty()) + // Scan the property list for material information + const PropertyList &list = shape->props; + for (size_t i = 0;i < list.length();i++) { - Pass *pass = material->getTechnique(0)->getPass(0); - /*TextureUnitState *txt =*/ - pass->createTextureUnitState(texName); + // Entries may be empty + if (list[i].empty()) continue; - pass->setVertexColourTracking(TVC_DIFFUSE); + const Property *pr = list[i].getPtr(); + if (pr->recType == RC_NiTexturingProperty) + t = static_cast(pr); + else if (pr->recType == RC_NiMaterialProperty) + m = static_cast(pr); + else if (pr->recType == RC_NiAlphaProperty) + a = static_cast(pr); + else + warn("Skipped property type: "+pr->recName); + } - // As of yet UNTESTED code from Chris: - /*pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); - pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); - pass->setDepthCheckEnabled(true); - - // Add transparency if NiAlphaProperty was present - if (alphaFlags != -1) + // Texture + if (t && t->textures[0].inUse) + { + NiSourceTexture *st = t->textures[0].texture.getPtr(); + if (st->external) { - std::cout << "Alpha flags set!" << endl; - if ((alphaFlags&1)) + /* Bethesda at some at some point converted all their BSA + * textures from tga to dds for increased load speed, but all + * texture file name references were kept as .tga. + */ + texName = "textures\\" + st->filename; + if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) { - pass->setDepthWriteEnabled(false); - pass->setSceneBlending(getBlendFactor((alphaFlags>>1)&0xf), - getBlendFactor((alphaFlags>>5)&0xf)); + Ogre::String::size_type pos = texName.rfind('.'); + texName.replace(pos, texName.length(), ".dds"); + } + } + else warn("Found internal texture, ignoring."); + } + + // Alpha modifiers + if (a) + { + alphaFlags = a->flags; + alphaTest = a->data.threshold; + } + + // Material + if(m) + { + ambient = m->data.ambient; + diffuse = m->data.diffuse; + specular = m->data.specular; + emissive = m->data.emissive; + glossiness = m->data.glossiness; + alpha = m->data.alpha; + } + + Ogre::String matname = name; + if (m || !texName.empty()) + { + // Generate a hash out of all properties that can affect the material. + size_t h = 0; + boost::hash_combine(h, ambient.x); + boost::hash_combine(h, ambient.y); + boost::hash_combine(h, ambient.z); + boost::hash_combine(h, diffuse.x); + boost::hash_combine(h, diffuse.y); + boost::hash_combine(h, diffuse.z); + boost::hash_combine(h, specular.x); + boost::hash_combine(h, specular.y); + boost::hash_combine(h, specular.z); + boost::hash_combine(h, emissive.x); + boost::hash_combine(h, emissive.y); + boost::hash_combine(h, emissive.z); + boost::hash_combine(h, texName); + boost::hash_combine(h, vertexColour); + boost::hash_combine(h, alphaFlags); + + std::map::iterator itr = MaterialMap.find(h); + if (itr != MaterialMap.end()) + { + // a suitable material exists already - use it + return itr->second; + } + // not found, create a new one + MaterialMap.insert(std::make_pair(h, matname)); + } + + // No existing material like this. Create a new one. + sh::MaterialInstance* instance = sh::Factory::getInstance ().createMaterialInstance (matname, "openmw_objects_base"); + instance->setProperty ("ambient", sh::makeProperty ( + new sh::Vector3(ambient.x, ambient.y, ambient.z))); + + instance->setProperty ("diffuse", sh::makeProperty ( + new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + + instance->setProperty ("specular", sh::makeProperty ( + new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); + + instance->setProperty ("emissive", sh::makeProperty ( + new sh::Vector3(emissive.x, emissive.y, emissive.z))); + + instance->setProperty ("diffuseMap", sh::makeProperty(texName)); + + if (vertexColour) + instance->setProperty ("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); + + // Add transparency if NiAlphaProperty was present + if (alphaFlags != -1) + { + // The 237 alpha flags are by far the most common. Check + // NiAlphaProperty in nif/property.h if you need to decode + // other values. 237 basically means normal transparencly. + if (alphaFlags == 237) + { + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); + if (result.first) + { + instance->setProperty("alpha_rejection", + sh::makeProperty(new sh::StringValue("greater_equal " + boost::lexical_cast(result.second)))); } else - pass->setDepthWriteEnabled(true); - - if ((alphaFlags>>9)&1) - pass->setAlphaRejectSettings(getTestMode((alphaFlags>>10)&0x7), - alphaTest); - - pass->setTransparentSortingEnabled(!((alphaFlags>>13)&1)); + { + // Enable transparency + instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue("off"))); + } } else - pass->setDepthWriteEnabled(true); */ - - - // Add transparency if NiAlphaProperty was present - if (alphaFlags != -1) - { - // The 237 alpha flags are by far the most common. Check - // NiAlphaProperty in nif/property.h if you need to decode - // other values. 237 basically means normal transparencly. - if (alphaFlags == 237) - { - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); - if (result.first) - { - pass->setAlphaRejectFunction(CMPF_GREATER_EQUAL); - pass->setAlphaRejectValue(result.second); - } - else - { - // Enable transparency - pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); - - //pass->setDepthCheckEnabled(false); - pass->setDepthWriteEnabled(false); - //std::cout << "alpha 237; material: " << name << " texName: " << texName << std::endl; - } - } - else - warn("Unhandled alpha setting for texture " + texName); - } - else - { - material->getTechnique(0)->setShadowCasterMaterial("depth_shadow_caster_noalpha"); - } - } - - if (Settings::Manager::getBool("enabled", "Shadows")) - { - bool split = Settings::Manager::getBool("split", "Shadows"); - const int numsplits = 3; - for (int i = 0; i < (split ? numsplits : 1); ++i) - { - TextureUnitState* tu = material->getTechnique(0)->getPass(0)->createTextureUnitState(); - tu->setName("shadowMap" + StringConverter::toString(i)); - tu->setContentType(TextureUnitState::CONTENT_SHADOW); - tu->setTextureAddressingMode(TextureUnitState::TAM_BORDER); - tu->setTextureBorderColour(ColourValue::White); - } - } - - if (Settings::Manager::getBool("shaders", "Objects")) - { - material->getTechnique(0)->getPass(0)->setVertexProgram("main_vp"); - material->getTechnique(0)->getPass(0)->setFragmentProgram("main_fp"); - - material->getTechnique(0)->getPass(0)->setFog(true); // force-disable fixed function fog, it is calculated in shader - } - - // Create a fallback technique without shadows and without mrt - Technique* tech2 = material->createTechnique(); - tech2->setSchemeName("Fallback"); - Pass* pass2 = tech2->createPass(); - pass2->createTextureUnitState(texName); - pass2->setVertexColourTracking(TVC_DIFFUSE); - if (Settings::Manager::getBool("shaders", "Objects")) - { - pass2->setVertexProgram("main_fallback_vp"); - pass2->setFragmentProgram("main_fallback_fp"); - pass2->setFog(true); // force-disable fixed function fog, it is calculated in shader - } - - // Add material bells and whistles - material->setAmbient(ambient.array[0], ambient.array[1], ambient.array[2]); - material->setDiffuse(diffuse.array[0], diffuse.array[1], diffuse.array[2], alpha); - material->setSpecular(specular.array[0], specular.array[1], specular.array[2], alpha); - material->setSelfIllumination(emissive.array[0], emissive.array[1], emissive.array[2]); - material->setShininess(glossiness); -} - -// Takes a name and adds a unique part to it. This is just used to -// make sure that all materials are given unique names. -String NIFLoader::getUniqueName(const String &input) -{ - static int addon = 0; - static char buf[8]; - snprintf(buf, 8, "_%d", addon++); - - // Don't overflow the buffer - if (addon > 999999) addon = 0; - - return input + buf; -} - -// Check if the given texture name exists in the real world. If it -// does not, change the string IN PLACE to say .dds instead and try -// that. The texture may still not exist, but no information of value -// is lost in that case. -void NIFLoader::findRealTexture(String &texName) -{ - assert(vfs); - if (vfs->isFile(texName)) return; - - int len = texName.size(); - if (len < 4) return; - - // Change texture extension to .dds - texName[len-3] = 'd'; - texName[len-2] = 'd'; - texName[len-1] = 's'; -} - -//Handle node at top - -// Convert Nif::NiTriShape to Ogre::SubMesh, attached to the given -// mesh. -void NIFLoader::createOgreSubMesh(NiTriShape *shape, const String &material, std::list &vertexBoneAssignments) -{ - // cout << "s:" << shape << "\n"; - NiTriShapeData *data = shape->data.getPtr(); - SubMesh *sub = mesh->createSubMesh(shape->name.toString()); - - int nextBuf = 0; - - // This function is just one long stream of Ogre-barf, but it works - // great. - - // Add vertices - int numVerts = data->vertices.length / 3; - sub->vertexData = new VertexData(); - sub->vertexData->vertexCount = numVerts; - sub->useSharedVertices = false; - - VertexDeclaration *decl = sub->vertexData->vertexDeclaration; - decl->addElement(nextBuf, 0, VET_FLOAT3, VES_POSITION); - - HardwareVertexBufferSharedPtr vbuf = - HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT3), - numVerts, HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false); - - if(flip) - { - float *datamod = new float[data->vertices.length]; - //std::cout << "Shape" << shape->name.toString() << "\n"; - for(int i = 0; i < numVerts; i++) - { - int index = i * 3; - const float *pos = data->vertices.ptr + index; - Ogre::Vector3 original = Ogre::Vector3(*pos ,*(pos+1), *(pos+2)); - original = mTransform * original; - mBoundingBox.merge(original); - datamod[index] = original.x; - datamod[index+1] = original.y; - datamod[index+2] = original.z; - } - vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); - delete [] datamod; - } - else - { - vbuf->writeData(0, vbuf->getSizeInBytes(), data->vertices.ptr, false); - } - - - VertexBufferBinding* bind = sub->vertexData->vertexBufferBinding; - bind->setBinding(nextBuf++, vbuf); - - if (data->normals.length) - { - decl->addElement(nextBuf, 0, VET_FLOAT3, VES_NORMAL); - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT3), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY, false); - - if(flip) - { - Quaternion rotation = mTransform.extractQuaternion(); - rotation.normalise(); - - float *datamod = new float[data->normals.length]; - for(int i = 0; i < numVerts; i++) - { - int index = i * 3; - const float *pos = data->normals.ptr + index; - Ogre::Vector3 original = Ogre::Vector3(*pos ,*(pos+1), *(pos+2)); - original = rotation * original; - if (mNormaliseNormals) - { - original.normalise(); - } - - - datamod[index] = original.x; - datamod[index+1] = original.y; - datamod[index+2] = original.z; - } - vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); - delete [] datamod; - } - else - { - vbuf->writeData(0, vbuf->getSizeInBytes(), data->normals.ptr, false); - } - bind->setBinding(nextBuf++, vbuf); - } - - - // Vertex colors - if (data->colors.length) - { - const float *colors = data->colors.ptr; - RenderSystem* rs = Root::getSingleton().getRenderSystem(); - std::vector colorsRGB(numVerts); - RGBA *pColour = &colorsRGB.front(); - for (int i=0; iconvertColourValue(ColourValue(colors[0],colors[1],colors[2], - colors[3]),pColour++); - colors += 4; - } - decl->addElement(nextBuf, 0, VET_COLOUR, VES_DIFFUSE); - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_COLOUR), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY); - vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB.front(), true); - bind->setBinding(nextBuf++, vbuf); - } - - if (data->uvlist.length) - { - - decl->addElement(nextBuf, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES); - vbuf = HardwareBufferManager::getSingleton().createVertexBuffer( - VertexElement::getTypeSize(VET_FLOAT2), - numVerts, HardwareBuffer::HBU_STATIC_WRITE_ONLY,false); - - if(flip) - { - float *datamod = new float[data->uvlist.length]; - - for(unsigned int i = 0; i < data->uvlist.length; i+=2){ - float x = *(data->uvlist.ptr + i); - - float y = *(data->uvlist.ptr + i + 1); - - datamod[i] =x; - datamod[i + 1] =y; - } - vbuf->writeData(0, vbuf->getSizeInBytes(), datamod, false); - delete [] datamod; - } - else - vbuf->writeData(0, vbuf->getSizeInBytes(), data->uvlist.ptr, false); - bind->setBinding(nextBuf++, vbuf); - } - - // Triangle faces - The total number of triangle points - int numFaces = data->triangles.length; - - if (numFaces) - { - - sub->indexData->indexCount = numFaces; - sub->indexData->indexStart = 0; - HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton(). - createIndexBuffer(HardwareIndexBuffer::IT_16BIT, - numFaces, - HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); - - if(flip && mFlipVertexWinding && sub->indexData->indexCount % 3 == 0){ - - sub->indexData->indexBuffer = ibuf; - - uint16 *datamod = new uint16[numFaces]; - int index = 0; - for (size_t i = 0; i < sub->indexData->indexCount; i+=3) - { - - const short *pos = data->triangles.ptr + index; - uint16 i0 = (uint16) *(pos+0); - uint16 i1 = (uint16) *(pos+1); - uint16 i2 = (uint16) *(pos+2); - - //std::cout << "i0: " << i0 << "i1: " << i1 << "i2: " << i2 << "\n"; - - - datamod[index] = i2; - datamod[index+1] = i1; - datamod[index+2] = i0; - - index += 3; - } - - ibuf->writeData(0, ibuf->getSizeInBytes(), datamod, false); - delete [] datamod; - - } - else - ibuf->writeData(0, ibuf->getSizeInBytes(), data->triangles.ptr, false); - sub->indexData->indexBuffer = ibuf; - } - - // Set material if one was given - if (!material.empty()) sub->setMaterialName(material); - - //add vertex bone assignments - - for (std::list::iterator it = vertexBoneAssignments.begin(); - it != vertexBoneAssignments.end(); it++) - { - sub->addBoneAssignment(*it); - } - if(mSkel.isNull()) - needBoneAssignments.push_back(sub); -} - -// Helper math functions. Reinventing linear algebra for the win! - -// Computes B = AxB (matrix*matrix) -static void matrixMul(const Matrix &A, Matrix &B) -{ - for (int i=0;i<3;i++) - { - float a = B.v[0].array[i]; - float b = B.v[1].array[i]; - float c = B.v[2].array[i]; - - B.v[0].array[i] = a*A.v[0].array[0] + b*A.v[0].array[1] + c*A.v[0].array[2]; - B.v[1].array[i] = a*A.v[1].array[0] + b*A.v[1].array[1] + c*A.v[1].array[2]; - B.v[2].array[i] = a*A.v[2].array[0] + b*A.v[2].array[1] + c*A.v[2].array[2]; - } -} - -// Computes C = B + AxC*scale -static void vectorMulAdd(const Matrix &A, const Vector &B, float *C, float scale) -{ - // Keep the original values - float a = C[0]; - float b = C[1]; - float c = C[2]; - - // Perform matrix multiplication, scaling and addition - for (int i=0;i<3;i++) - C[i] = B.array[i] + (a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2])*scale; -} - -// Computes B = AxB (matrix*vector) -static void vectorMul(const Matrix &A, float *C) -{ - // Keep the original values - float a = C[0]; - float b = C[1]; - float c = C[2]; - - // Perform matrix multiplication, scaling and addition - for (int i=0;i<3;i++) - C[i] = a*A.v[i].array[0] + b*A.v[i].array[1] + c*A.v[i].array[2]; -} - - -void NIFLoader::handleNiTriShape(NiTriShape *shape, int flags, BoundsFinder &bounds, Transformation original, std::vector boneSequence) -{ - assert(shape != NULL); - - bool saveTheShape = inTheSkeletonTree; - // Interpret flags - bool hidden = (flags & 0x01) != 0; // Not displayed - bool collide = (flags & 0x02) != 0; // Use mesh for collision - bool bbcollide = (flags & 0x04) != 0; // Use bounding box for collision - - // Bounding box collision isn't implemented, always use mesh for now. - if (bbcollide) - { - collide = true; - bbcollide = false; - } - - // If the object was marked "NCO" earlier, it shouldn't collide with - // anything. - if (flags & 0x800) - { - collide = false; - bbcollide = false; - } - - if (!collide && !bbcollide && hidden) - // This mesh apparently isn't being used for anything, so don't - // bother setting it up. - return; - - // Material name for this submesh, if any - String material; - - // Skip the entire material phase for hidden nodes - if (!hidden) - { - // These are set below if present - NiTexturingProperty *t = NULL; - NiMaterialProperty *m = NULL; - NiAlphaProperty *a = NULL; - - // Scan the property list for material information - PropertyList &list = shape->props; - int n = list.length(); - for (int i=0; irecType == RC_NiTexturingProperty) - t = static_cast(pr); - else if (pr->recType == RC_NiMaterialProperty) - m = static_cast(pr); - else if (pr->recType == RC_NiAlphaProperty) - a = static_cast(pr); - } - - // Texture - String texName; - if (t && t->textures[0].inUse) - { - NiSourceTexture *st = t->textures[0].texture.getPtr(); - if (st->external) - { - SString tname = st->filename; - - /* findRealTexture checks if the file actually - exists. If it doesn't, and the name ends in .tga, it - will try replacing the extension with .dds instead - and search for that. Bethesda at some at some point - converted all their BSA textures from tga to dds for - increased load speed, but all texture file name - references were kept as .tga. - - The function replaces the name in place (that's why - we cast away the const modifier), but this is no - problem since all the nif data is stored in a local - throwaway buffer. - */ - texName = "textures\\" + tname.toString(); - findRealTexture(texName); - } - else warn("Found internal texture, ignoring."); - } - - // Alpha modifiers - int alphaFlags = -1; - ubyte alphaTest = 0; - if (a) - { - alphaFlags = a->flags; - alphaTest = a->data->threshold; - } - - // Material - if (m || !texName.empty()) - { - // If we're here, then this mesh has a material. Thus we - // need to calculate a snappy material name. It should - // contain the mesh name (mesh->getName()) but also has to - // be unique. One mesh may use many materials. - material = getUniqueName(mesh->getName()); - - if (m) - { - // Use NiMaterialProperty data to create the data - const S_MaterialProperty *d = m->data; - - std::multimap::iterator itr = MaterialMap.find(texName); - std::multimap::iterator lastElement; - lastElement = MaterialMap.upper_bound(texName); - if (itr != MaterialMap.end()) - { - for ( ; itr != lastElement; ++itr) - { - //std::cout << "OK!"; - //MaterialPtr mat = MaterialManager::getSingleton().getByName(itr->second,recourceGroup); - material = itr->second; - //if( mat->getA - } - } - else - { - //std::cout << "new"; - createMaterial(material, d->ambient, d->diffuse, d->specular, d->emissive, - d->glossiness, d->alpha, alphaFlags, alphaTest, texName); - MaterialMap.insert(std::make_pair(texName,material)); - } - } - else - { - // We only have a texture name. Create a default - // material for it. - Vector zero, one; - for (int i=0; i<3;i++) - { - zero.array[i] = 0.0; - one.array[i] = 1.0; - } - - createMaterial(material, one, one, zero, zero, 0.0, 1.0, - alphaFlags, alphaTest, texName); - } - } - } // End of material block, if(!hidden) ... - - /* Do in-place transformation of all the vertices and normals. This - is pretty messy stuff, but we need it to make the sub-meshes - appear in the correct place. Neither Ogre nor Bullet support - nested levels of sub-meshes with transformations applied to each - level. - */ - NiTriShapeData *data = shape->data.getPtr(); - int numVerts = data->vertices.length / 3; - - float *ptr = (float*)data->vertices.ptr; - float *optr = ptr; - - std::list vertexBoneAssignments; - - Nif::NiTriShapeCopy copy = shape->clone(); - - if(!shape->controller.empty()) - { - Nif::Controller* cont = shape->controller.getPtr(); - if(cont->recType == RC_NiGeomMorpherController) - { - Nif::NiGeomMorpherController* morph = dynamic_cast (cont); - copy.morph = morph->data.get(); - copy.morph.setStartTime(morph->timeStart); - copy.morph.setStopTime(morph->timeStop); - saveTheShape = true; - } - - } - //use niskindata for the position of vertices. - if (!shape->skin.empty()) - { - - - - // vector that stores if the position of a vertex is absolute - std::vector vertexPosAbsolut(numVerts,false); - std::vector vertexPosOriginal(numVerts, Ogre::Vector3::ZERO); - std::vector vertexNormalOriginal(numVerts, Ogre::Vector3::ZERO); - - float *ptrNormals = (float*)data->normals.ptr; - //the bone from skin->bones[boneIndex] is linked to skin->data->bones[boneIndex] - //the first one contains a link to the bone, the second vertex transformation - //relative to the bone - int boneIndex = 0; - Bone *bonePtr; - Vector3 vecPos; - Quaternion vecRot; - - std::vector boneList = shape->skin->data->bones; - - /* - Iterate through the boneList which contains what vertices are linked to - the bone (it->weights array) and at what position (it->trafo) - That position is added to every vertex. - */ - for (std::vector::iterator it = boneList.begin(); - it != boneList.end(); it++) - { - if(mSkel.isNull()) - { - std::cout << "No skeleton for :" << shape->skin->bones[boneIndex].name.toString() << std::endl; - break; - } - //get the bone from bones array of skindata - if(!mSkel->hasBone(shape->skin->bones[boneIndex].name.toString())) - std::cout << "We don't have this bone"; - bonePtr = mSkel->getBone(shape->skin->bones[boneIndex].name.toString()); - - // final_vector = old_vector + old_rotation*new_vector*old_scale - - - Nif::NiSkinData::BoneInfoCopy boneinfocopy; - boneinfocopy.trafo.rotation = convertRotation(it->trafo->rotation); - boneinfocopy.trafo.trans = convertVector3(it->trafo->trans); - boneinfocopy.bonename = shape->skin->bones[boneIndex].name.toString(); - boneinfocopy.bonehandle = bonePtr->getHandle(); - copy.boneinfo.push_back(boneinfocopy); - for (unsigned int i=0; iweights.length; i++) - { - vecPos = bonePtr->_getDerivedPosition() + - bonePtr->_getDerivedOrientation() * convertVector3(it->trafo->trans); - - vecRot = bonePtr->_getDerivedOrientation() * convertRotation(it->trafo->rotation); - unsigned int verIndex = (it->weights.ptr + i)->vertex; - //boneinfo.weights.push_back(*(it->weights.ptr + i)); - Nif::NiSkinData::IndividualWeight ind; - ind.weight = (it->weights.ptr + i)->weight; - ind.boneinfocopyindex = copy.boneinfo.size() - 1; - if(copy.vertsToWeights.find(verIndex) == copy.vertsToWeights.end()) - { - std::vector blank; - blank.push_back(ind); - copy.vertsToWeights[verIndex] = blank; - } - else - { - copy.vertsToWeights[verIndex].push_back(ind); - } - - //Check if the vertex is relativ, FIXME: Is there a better solution? - if (vertexPosAbsolut[verIndex] == false) - { - //apply transformation to the vertices - Vector3 absVertPos = vecPos + vecRot * Vector3(ptr + verIndex *3); - absVertPos = absVertPos * (it->weights.ptr + i)->weight; - vertexPosOriginal[verIndex] = Vector3(ptr + verIndex *3); - - mBoundingBox.merge(absVertPos); - //convert it back to float * - for (int j=0; j<3; j++) - (ptr + verIndex*3)[j] = absVertPos[j]; - - //apply rotation to the normals (not every vertex has a normal) - //FIXME: I guessed that vertex[i] = normal[i], is that true? - if (verIndex < data->normals.length) - { - Vector3 absNormalsPos = vecRot * Vector3(ptrNormals + verIndex *3); - absNormalsPos = absNormalsPos * (it->weights.ptr + i)->weight; - vertexNormalOriginal[verIndex] = Vector3(ptrNormals + verIndex *3); - - for (int j=0; j<3; j++) - (ptrNormals + verIndex*3)[j] = absNormalsPos[j]; - } - - vertexPosAbsolut[verIndex] = true; - } - else - { - Vector3 absVertPos = vecPos + vecRot * vertexPosOriginal[verIndex]; - absVertPos = absVertPos * (it->weights.ptr + i)->weight; - Vector3 old = Vector3(ptr + verIndex *3); - absVertPos = absVertPos + old; - - mBoundingBox.merge(absVertPos); - //convert it back to float * - for (int j=0; j<3; j++) - (ptr + verIndex*3)[j] = absVertPos[j]; - - //apply rotation to the normals (not every vertex has a normal) - //FIXME: I guessed that vertex[i] = normal[i], is that true? - if (verIndex < data->normals.length) - { - Vector3 absNormalsPos = vecRot * vertexNormalOriginal[verIndex]; - absNormalsPos = absNormalsPos * (it->weights.ptr + i)->weight; - Vector3 oldNormal = Vector3(ptrNormals + verIndex *3); - absNormalsPos = absNormalsPos + oldNormal; - - for (int j=0; j<3; j++) - (ptrNormals + verIndex*3)[j] = absNormalsPos[j]; - } - } - - - VertexBoneAssignment vba; - vba.boneIndex = bonePtr->getHandle(); - vba.vertexIndex = verIndex; - vba.weight = (it->weights.ptr + i)->weight; - - - vertexBoneAssignments.push_back(vba); - } - - - boneIndex++; - } - - + warn("Unhandled alpha setting for texture " + texName); } else + instance->getMaterial ()->setShadowCasterMaterial ("openmw_shadowcaster_noalpha"); + + // As of yet UNTESTED code from Chris: + /*pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC); + pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL); + pass->setDepthCheckEnabled(true); + + // Add transparency if NiAlphaProperty was present + if (alphaFlags != -1) { - - copy.boneSequence = boneSequence; - // Rotate, scale and translate all the vertices, - const Matrix &rot = shape->trafo->rotation; - const Vector &pos = shape->trafo->pos; - float scale = shape->trafo->scale; - - copy.trafo.trans = convertVector3(original.pos); - copy.trafo.rotation = convertRotation(original.rotation); - copy.trafo.scale = original.scale; - //We don't use velocity for anything yet, so it does not need to be saved - - // Computes C = B + AxC*scale - for (int i=0; isetDepthWriteEnabled(false); + pass->setSceneBlending(getBlendFactor((alphaFlags>>1)&0xf), + getBlendFactor((alphaFlags>>5)&0xf)); } + else + pass->setDepthWriteEnabled(true); - // Remember to rotate all the vertex normals as well - if (data->normals.length) + if ((alphaFlags>>9)&1) + pass->setAlphaRejectSettings(getTestMode((alphaFlags>>10)&0x7), + alphaTest); + + pass->setTransparentSortingEnabled(!((alphaFlags>>13)&1)); + } +*/ + + return matname; +} + +}; +std::map NIFMaterialLoader::MaterialMap; + + +class NIFMeshLoader : Ogre::ManualResourceLoader +{ + std::string mName; + std::string mGroup; + std::string mShapeName; + std::string mMaterialName; + std::string mSkelName; + + void warn(const std::string &msg) + { + std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + } + + void fail(const std::string &msg) + { + std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + abort(); + } + + + // Convert NiTriShape to Ogre::SubMesh + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape *shape) + { + Ogre::SkeletonPtr skel; + const Nif::NiTriShapeData *data = shape->data.getPtr(); + const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); + std::vector srcVerts = data->vertices; + std::vector srcNorms = data->normals; + if(skin != NULL) { - ptr = (float*)data->normals.ptr; - for (int i=0; isetSkeletonName(mSkelName); + + // Get the skeleton resource, so vertices can be transformed into the bones' initial state. + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + skel = skelMgr->getByName(mSkelName); + skel->touch(); + + // Convert vertices and normals to bone space from bind position. It would be + // better to transform the bones into bind position, but there doesn't seem to + // be a reliable way to do that. + std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); + std::vector newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) { - vectorMul(rot, ptr); - ptr += 3; - } - } - if(!mSkel.isNull() ){ - int boneIndex; - - boneIndex = mSkel->getNumBones() - 1; - for(int i = 0; i < numVerts; i++){ - VertexBoneAssignment vba; - vba.boneIndex = boneIndex; - vba.vertexIndex = i; - vba.weight = 1; - vertexBoneAssignments.push_back(vba); - } - } - } + Ogre::Bone *bone = skel->getBone(bones[b]->name); + Ogre::Matrix4 mat, mat2; + mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), + Ogre::Quaternion(data->bones[b].trafo.rotation)); + mat2.makeTransform(bone->_getDerivedPosition(), bone->_getDerivedScale(), + bone->_getDerivedOrientation()); + mat = mat2 * mat; - if (!hidden) - { - // Add this vertex set to the bounding box - bounds.add(optr, numVerts); - if(saveTheShape) - shapes.push_back(copy); - - // Create the submesh - createOgreSubMesh(shape, material, vertexBoneAssignments); - } -} - -void NIFLoader::calculateTransform() -{ - // Calculate transform - Matrix4 transform = Matrix4::IDENTITY; - transform = Matrix4::getScale(vector) * transform; - - // Check whether we have to flip vertex winding. - // We do have to, if we changed our right hand base. - // We can test it by using the cross product from X and Y and see, if it is a non-negative - // projection on Z. Actually it should be exactly Z, as we don't do non-uniform scaling yet, - // but the test is cheap either way. - Matrix3 m3; - transform.extract3x3Matrix(m3); - - if (m3.GetColumn(0).crossProduct(m3.GetColumn(1)).dotProduct(m3.GetColumn(2)) < 0) - { - mFlipVertexWinding = true; - } - - mTransform = transform; -} -void NIFLoader::handleNode(Nif::Node *node, int flags, - const Transformation *trafo, BoundsFinder &bounds, Ogre::Bone *parentBone, std::vector boneSequence) -{ - // Accumulate the flags from all the child nodes. This works for all - // the flags we currently use, at least. - flags |= node->flags; - - // Check for extra data - Extra *e = node; - while (!e->extra.empty()) - { - // Get the next extra data in the list - e = e->extra.getPtr(); - assert(e != NULL); - - if (e->recType == RC_NiStringExtraData) - { - // String markers may contain important information - // affecting the entire subtree of this node - NiStringExtraData *sd = (NiStringExtraData*)e; - - if (sd->string == "NCO") - // No collision. Use an internal flag setting to mark this. - flags |= 0x800; - else if (sd->string == "MRK") - // Marker objects. These are only visible in the - // editor. Until and unless we add an editor component to - // the engine, just skip this entire node. - return; - } - - if (e->recType == RC_NiTextKeyExtraData){ - Nif::NiTextKeyExtraData* extra = dynamic_cast (e); - - std::ofstream file; - - if(mOutputAnimFiles){ - std::string cut = ""; - for(unsigned int i = 0; i < resourcename.length(); i++) + const std::vector &weights = data->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) { - if(!(resourcename.at(i) == '\\' || resourcename.at(i) == '/' || resourcename.at(i) == '>' || resourcename.at(i) == '<' || resourcename.at(i) == '?' || resourcename.at(i) == '*' || resourcename.at(i) == '|' || resourcename.at(i) == ':' || resourcename.at(i) == '"')) + size_t index = weights[i].vertex; + float weight = weights[i].weight; + + newVerts.at(index) += (mat*srcVerts[index]) * weight; + if(newNorms.size() > index) { - cut += resourcename.at(i); - } - } - - std::cout << "Outputting " << cut << "\n"; - - file.open((verbosePath + "/Indices" + cut + ".txt").c_str()); - } - - for(std::vector::iterator textiter = extra->list.begin(); textiter != extra->list.end(); textiter++) - { - std::string text = textiter->text.toString(); - - replace(text.begin(), text.end(), '\n', '/'); - - text.erase(std::remove(text.begin(), text.end(), '\r'), text.end()); - std::size_t i = 0; - while(i < text.length()){ - while(i < text.length() && text.at(i) == '/' ){ - i++; - } - std::size_t first = i; - int length = 0; - while(i < text.length() && text.at(i) != '/' ){ - i++; - length++; - } - if(first < text.length()){ - //length = text.length() - first; - std::string sub = text.substr(first, length); - - if(mOutputAnimFiles) - file << "Time: " << textiter->time << "|" << sub << "\n"; - - textmappings[sub] = textiter->time; + Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); + vec4 = mat*vec4 * weight; + newNorms[index] += Ogre::Vector3(&vec4[0]); } } } - file.close(); + + srcVerts = newVerts; + srcNorms = newNorms; } + else if(mSkelName.length() == 0) + { + // No skinning and no skeleton, so just transform the vertices and + // normals into position. + Ogre::Matrix4 mat4 = shape->getWorldTransform(); + for(size_t i = 0;i < srcVerts.size();i++) + { + Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); + vec4 = mat4*vec4; + srcVerts[i] = Ogre::Vector3(&vec4[0]); + } + for(size_t i = 0;i < srcNorms.size();i++) + { + Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); + vec4 = mat4*vec4; + srcNorms[i] = Ogre::Vector3(&vec4[0]); + } + } + + // Set the bounding box first + BoundsFinder bounds; + bounds.add(&srcVerts[0][0], srcVerts.size()); + // No idea why this offset is needed. It works fine without it if the + // vertices weren't transformed first, but otherwise it fails later on + // when the object is being inserted into the scene. + mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, + bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); + mesh->_setBoundingSphereRadius(bounds.getRadius()); + + // This function is just one long stream of Ogre-barf, but it works + // great. + Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); + Ogre::HardwareVertexBufferSharedPtr vbuf; + Ogre::HardwareIndexBufferSharedPtr ibuf; + Ogre::VertexBufferBinding *bind; + Ogre::VertexDeclaration *decl; + int nextBuf = 0; + + Ogre::SubMesh *sub = mesh->createSubMesh(shape->name); + + // Add vertices + sub->useSharedVertices = false; + sub->vertexData = new Ogre::VertexData(); + sub->vertexData->vertexStart = 0; + sub->vertexData->vertexCount = srcVerts.size(); + + decl = sub->vertexData->vertexDeclaration; + bind = sub->vertexData->vertexBufferBinding; + if(srcVerts.size()) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), + srcVerts.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, + true); + vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); + bind->setBinding(nextBuf++, vbuf); + } + + // Vertex normals + if(srcNorms.size()) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), + srcNorms.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, + true); + vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); + bind->setBinding(nextBuf++, vbuf); + } + + // Vertex colors + const std::vector &colors = data->colors; + if(colors.size()) + { + Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); + std::vector colorsRGB(colors.size()); + for(size_t i = 0;i < colorsRGB.size();i++) + { + Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); + rs->convertColourValue(clr, &colorsRGB[i]); + } + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), + colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, + true); + vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); + decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); + bind->setBinding(nextBuf++, vbuf); + } + + // Texture UV coordinates + size_t numUVs = data->uvlist.size(); + if(numUVs) + { + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size()*numUVs, + Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); + for(size_t i = 0;i < numUVs;i++) + { + const std::vector &uvlist = data->uvlist[i]; + vbuf->writeData(i*srcVerts.size()*elemSize, elemSize*srcVerts.size(), &uvlist[0], true); + decl->addElement(nextBuf, i*srcVerts.size()*elemSize, Ogre::VET_FLOAT2, + Ogre::VES_TEXTURE_COORDINATES, i); + } + bind->setBinding(nextBuf++, vbuf); + } + + // Triangle faces + const std::vector &srcIdx = data->triangles; + if(srcIdx.size()) + { + ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), + Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); + ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); + sub->indexData->indexBuffer = ibuf; + sub->indexData->indexCount = srcIdx.size(); + sub->indexData->indexStart = 0; + } + + // Assign bone weights for this TriShape + if(skin != NULL) + { + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t i = 0;i < bones.length();i++) + { + Ogre::VertexBoneAssignment boneInf; + boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); + + const std::vector &weights = data->bones[i].weights; + for(size_t j = 0;j < weights.size();j++) + { + boneInf.vertexIndex = weights[j].vertex; + boneInf.weight = weights[j].weight; + sub->addBoneAssignment(boneInf); + } + } + } + + if(mMaterialName.length() > 0) + sub->setMaterialName(mMaterialName); } - Bone *bone = 0; - - // create skeleton or add bones - if (node->recType == RC_NiNode) + bool findTriShape(Ogre::Mesh *mesh, Nif::Node *node) { - //FIXME: "Bip01" isn't every time the root bone - if (node->name == "Bip01" || node->name == "Root Bone") //root node, create a skeleton + if(node->recType == Nif::RC_NiTriShape && mShapeName == node->name) { - inTheSkeletonTree = true; - - mSkel = SkeletonManager::getSingleton().create(getSkeletonName(), resourceGroup, true); + handleNiTriShape(mesh, dynamic_cast(node)); + return true; } - else if (!mSkel.isNull() && !parentBone) - inTheSkeletonTree = false; - if (!mSkel.isNull()) //if there is a skeleton + Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) { - std::string name = node->name.toString(); - - // Quick-n-dirty workaround for the fact that several - // bones may have the same name. - if(!mSkel->hasBone(name)) + Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) { - boneSequence.push_back(name); - bone = mSkel->createBone(name); + if(!children[i].empty()) + { + if(findTriShape(mesh, children[i].getPtr())) + return true; + } + } + } + return false; + } - if (parentBone) - parentBone->addChild(bone); - bone->setInheritOrientation(true); - bone->setPosition(convertVector3(node->trafo->pos)); - bone->setOrientation(convertRotation(node->trafo->rotation)); + typedef std::map LoaderMap; + static LoaderMap sLoaders; + +public: + NIFMeshLoader() + { } + NIFMeshLoader(const std::string &name, const std::string &group, const std::string skelName) + : mName(name), mGroup(group), mSkelName(skelName) + { } + + virtual void loadResource(Ogre::Resource *resource) + { + Ogre::Mesh *mesh = dynamic_cast(resource); + assert(mesh && "Attempting to load a mesh into a non-mesh resource!"); + + if(!mShapeName.length()) + { + if(mSkelName.length() > 0) + mesh->setSkeletonName(mSkelName); + return; + } + + Nif::NIFFile nif(mName); + Nif::Node *node = dynamic_cast(nif.getRecord(0)); + findTriShape(mesh, node); + } + + void createMeshes(const Nif::Node *node, MeshPairList &meshes, int flags=0) + { + flags |= node->flags; + + Nif::ExtraPtr e = node->extra; + while(!e.empty()) + { + Nif::NiStringExtraData *sd; + Nif::NiTextKeyExtraData *td; + if((sd=dynamic_cast(e.getPtr())) != NULL) + { + // String markers may contain important information + // affecting the entire subtree of this obj + if(sd->string == "MRK") + { + // Marker objects. These are only visible in the + // editor. + flags |= 0x01; + } + } + else if((td=dynamic_cast(e.getPtr())) != NULL) + { + // TODO: Read and store text keys somewhere + } + else + warn("Unhandled extra data type "+e->recName); + e = e->extra; + } + + if(node->recType == Nif::RC_NiTriShape) + { + const NiTriShape *shape = dynamic_cast(node); + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + std::string fullname = mName+"@shape="+shape->name; + if(mSkelName.length() > 0 && mName != mSkelName) + fullname += "@skel="+mSkelName; + + std::transform(fullname.begin(), fullname.end(), fullname.begin(), ::tolower); + Ogre::MeshPtr mesh = meshMgr.getByName(fullname); + if(mesh.isNull()) + { + NIFMeshLoader *loader = &sLoaders[fullname]; + *loader = *this; + if(!(flags&0x01)) // Not hidden + { + loader->mShapeName = shape->name; + loader->mMaterialName = NIFMaterialLoader::getMaterial(shape, fullname, mGroup); + } + + mesh = meshMgr.createManual(fullname, mGroup, loader); + } + + meshes.push_back(std::make_pair(mesh, shape->name)); + } + else if(node->recType != Nif::RC_NiNode && node->recType != Nif::RC_RootCollisionNode && + node->recType != Nif::RC_NiRotatingParticles) + warn("Unhandled mesh node type: "+node->recName); + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + createMeshes(children[i].getPtr(), meshes, flags); } } } - Transformation original = *(node->trafo); - // Apply the parent transformation to this node. We overwrite the - // existing data with the final transformation. - if (trafo) - { - // Get a non-const reference to the node's data, since we're - // overwriting it. TODO: Is this necessary? - Transformation &final = *((Transformation*)node->trafo); +}; +NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; - // For both position and rotation we have that: - // final_vector = old_vector + old_rotation*new_vector*old_scale - vectorMulAdd(trafo->rotation, trafo->pos, final.pos.array, trafo->scale); - vectorMulAdd(trafo->rotation, trafo->velocity, final.velocity.array, trafo->scale); - // Merge the rotations together - matrixMul(trafo->rotation, final.rotation); - - // Scalar values are so nice to deal with. Why can't everything - // just be scalar? - final.scale *= trafo->scale; - } - - // For NiNodes, loop through children - if (node->recType == RC_NiNode) - { - NodeList &list = ((NiNode*)node)->children; - int n = list.length(); - for (int i = 0; itrafo, bounds, bone, boneSequence); - } - } - else if (node->recType == RC_NiTriShape && bNiTri) - { - std::string nodename = node->name.toString(); - - if (triname == "") - { - handleNiTriShape(dynamic_cast(node), flags, bounds, original, boneSequence); - } - else if(nodename.length() >= triname.length()) - { - std::transform(nodename.begin(), nodename.end(), nodename.begin(), ::tolower); - if(triname == nodename.substr(0, triname.length())) - handleNiTriShape(dynamic_cast(node), flags, bounds, original, boneSequence); - } - } -} - -void NIFLoader::loadResource(Resource *resource) +MeshPairList NIFLoader::load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group) { - inTheSkeletonTree = false; - allanim.clear(); - shapes.clear(); - needBoneAssignments.clear(); - // needBoneAssignments.clear(); - mBoundingBox.setNull(); - mesh = 0; - mSkel.setNull(); - flip = false; - resourcename = resource->getName(); - char suffix = resourcename.at(resourcename.length() - 2); - bool addAnim = true; - bool hasAnim = false; - bool linkSkeleton = true; - //bool baddin = false; - bNiTri = true; - if(resourcename == "meshes\\base_anim.nif" || resourcename == "meshes\\base_animkna.nif") - { - bNiTri = false; - } + MeshPairList meshes; - if(suffix == '*') - { - vector = Ogre::Vector3(-1,1,1); - flip = true; - } - else if(suffix == '?'){ - vector = Ogre::Vector3(1,-1,1); - flip = true; - } - else if(suffix == '<'){ - vector = Ogre::Vector3(1,1,-1); - flip = true; - } - else if(suffix == '>') - { - //baddin = true; - bNiTri = true; - std::string sub = resourcename.substr(resourcename.length() - 6, 4); - - if(sub.compare("0000") != 0) - addAnim = false; - - } - else if(suffix == ':') - { - //baddin = true; - linkSkeleton = false; - bNiTri = true; - std::string sub = resourcename.substr(resourcename.length() - 6, 4); - - if(sub.compare("0000") != 0) - addAnim = false; - - } - - switch(resourcename.at(resourcename.length() - 1)) - { - case '"': - triname = "tri chest"; - break; - case '*': - triname = "tri tail"; - break; - case ':': - triname = "tri left foot"; - break; - case '<': - triname = "tri right foot"; - break; - case '>': - triname = "tri left hand"; - break; - case '?': - triname = "tri right hand"; - break; - default: - triname = ""; - break; - } - if(flip) - { - calculateTransform(); - } - // Set up the VFS if it hasn't been done already - if (!vfs) vfs = new OgreVFS(resourceGroup); - - // Get the mesh - mesh = dynamic_cast(resource); - assert(mesh); - - // Look it up - resourceName = mesh->getName(); - //std::cout << resourceName << "\n"; - - if (!vfs->isFile(resourceName)) - { - warn("File "+resourceName+" not found."); - return; - } - - // Helper that computes bounding boxes for us. - BoundsFinder bounds; - - // Load the NIF. TODO: Wrap this in a try-catch block once we're out - // of the early stages of development. Right now we WANT to catch - // every error as early and intrusively as possible, as it's most - // likely a sign of incomplete code rather than faulty input. - NIFFile nif(vfs->open(resourceName), resourceName); + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + std::transform(skelName.begin(), skelName.end(), skelName.begin(), ::tolower); + Nif::NIFFile nif(name); if (nif.numRecords() < 1) { - warn("Found no records in NIF."); - return; + nif.warn("Found no records in NIF."); + return meshes; } // The first record is assumed to be the root node - Record *r = nif.getRecord(0); + Nif::Record *r = nif.getRecord(0); assert(r != NULL); Nif::Node *node = dynamic_cast(r); - - if (node == NULL) + if(node == NULL) { - warn("First record in file was not a node, but a " + - r->recName.toString() + ". Skipping file."); - return; + nif.warn("First record in file was not a node, but a "+ + r->recName+". Skipping file."); + return meshes; } - // Handle the node - std::vector boneSequence; + NIFSkeletonLoader skelldr; + bool hasSkel = skelldr.createSkeleton(skelName, group, textkeys, node); + NIFMeshLoader meshldr(name, group, (hasSkel ? skelName : std::string())); + meshldr.createMeshes(node, meshes); + return meshes; +} - handleNode(node, 0, NULL, bounds, 0, boneSequence); - if(addAnim) +EntityList NIFLoader::createEntities(Ogre::SceneNode *parent, TextKeyMap *textkeys, const std::string &name, const std::string &group) +{ + EntityList entitylist; + + MeshPairList meshes = load(name, name, textkeys, group); + if(meshes.size() == 0) + return entitylist; + + Ogre::SceneManager *sceneMgr = parent->getCreator(); + for(size_t i = 0;i < meshes.size();i++) { - for(int i = 0; i < nif.numRecords(); i++) + entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].first->getName())); + Ogre::Entity *entity = entitylist.mEntities.back(); + if(!entitylist.mSkelBase && entity->hasSkeleton()) + entitylist.mSkelBase = entity; + } + + if(entitylist.mSkelBase) + { + parent->attachObject(entitylist.mSkelBase); + for(size_t i = 0;i < entitylist.mEntities.size();i++) { - Nif::NiKeyframeController *f = dynamic_cast(nif.getRecord(i)); - - if(f != NULL) + Ogre::Entity *entity = entitylist.mEntities[i]; + if(entity != entitylist.mSkelBase && entity->hasSkeleton()) { - hasAnim = true; - Nif::Node *o = dynamic_cast(f->target.getPtr()); - Nif::NiKeyframeDataPtr data = f->data; + entity->shareSkeletonInstanceWith(entitylist.mSkelBase); + parent->attachObject(entity); + } + else if(entity != entitylist.mSkelBase) + entitylist.mSkelBase->attachObjectToBone(meshes[i].second, entity); + } + } + else + { + for(size_t i = 0;i < entitylist.mEntities.size();i++) + parent->attachObject(entitylist.mEntities[i]); + } - if (f->timeStart >= 10000000000000000.0f) - continue; - data->setBonename(o->name.toString()); - data->setStartTime(f->timeStart); - data->setStopTime(f->timeStop); + return entitylist; +} - allanim.push_back(data.get()); +struct checklow { + bool operator()(const char &a, const char &b) const + { + return ::tolower(a) == ::tolower(b); + } +}; + +EntityList NIFLoader::createEntities(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + const std::string &name, + const std::string &group) +{ + EntityList entitylist; + + MeshPairList meshes = load(name, parent->getMesh()->getSkeletonName(), NULL, group); + if(meshes.size() == 0) + return entitylist; + + Ogre::SceneManager *sceneMgr = parentNode->getCreator(); + std::string filter = "Tri "+bonename; + for(size_t i = 0;i < meshes.size();i++) + { + Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].first->getName()); + if(ent->hasSkeleton()) + { + if(meshes[i].second.length() < filter.length() || + std::mismatch(filter.begin(), filter.end(), meshes[i].second.begin(), checklow()).first != filter.end()) + { + sceneMgr->destroyEntity(ent); + meshes.erase(meshes.begin()+i); + i--; + continue; + } + if(!entitylist.mSkelBase) + entitylist.mSkelBase = ent; + } + entitylist.mEntities.push_back(ent); + } + + Ogre::Vector3 scale(1.0f); + if(bonename.find("Left") != std::string::npos) + scale.x *= -1.0f; + + if(entitylist.mSkelBase) + { + entitylist.mSkelBase->shareSkeletonInstanceWith(parent); + parentNode->attachObject(entitylist.mSkelBase); + for(size_t i = 0;i < entitylist.mEntities.size();i++) + { + Ogre::Entity *entity = entitylist.mEntities[i]; + if(entity != entitylist.mSkelBase && entity->hasSkeleton()) + { + entity->shareSkeletonInstanceWith(parent); + parentNode->attachObject(entity); + } + else if(entity != entitylist.mSkelBase) + { + Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); + tag->setScale(scale); } } } - // set the bounding value. - if (bounds.isValid()) + else { - mesh->_setBounds(AxisAlignedBox(bounds.minX(), bounds.minY(), bounds.minZ(), - bounds.maxX(), bounds.maxY(), bounds.maxZ())); - mesh->_setBoundingSphereRadius(bounds.getRadius()); - } - if(hasAnim && addAnim){ - allanimmap[resourcename] = allanim; - alltextmappings[resourcename] = textmappings; - } - if(!mSkel.isNull() && shapes.size() > 0 && addAnim) - { - allshapesmap[resourcename] = shapes; - - } - - if(flip){ - mesh->_setBounds(mBoundingBox, false); - } - - if (!mSkel.isNull() ) - { - for(std::vector::iterator iter = needBoneAssignments.begin(); iter != needBoneAssignments.end(); iter++) + for(size_t i = 0;i < entitylist.mEntities.size();i++) { - int boneIndex = mSkel->getNumBones() - 1; - VertexBoneAssignment vba; - vba.boneIndex = boneIndex; - vba.vertexIndex = 0; - vba.weight = 1; - - - (*iter)->addBoneAssignment(vba); + Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entitylist.mEntities[i]); + tag->setScale(scale); } - //Don't link on npc parts to eliminate redundant skeletons - //Will have to be changed later slightly for robes/skirts - if(linkSkeleton) - mesh->_notifySkeleton(mSkel); } + + return entitylist; } - - - -MeshPtr NIFLoader::load(const std::string &name, - const std::string &group) -{ - - MeshManager *m = MeshManager::getSingletonPtr(); - // Check if the resource already exists - ResourcePtr ptr = m->getByName(name, group); - MeshPtr themesh; - if (!ptr.isNull()){ - themesh = MeshPtr(ptr); - } - else // Nope, create a new one. - { - themesh = MeshManager::getSingleton().createManual(name, group, NIFLoader::getSingletonPtr()); - } - return themesh; -} - - -std::vector* NIFLoader::getAnim(std::string lowername){ - - std::map,ciLessBoost>::iterator iter = allanimmap.find(lowername); - std::vector* pass = 0; - if(iter != allanimmap.end()) - pass = &(iter->second); - return pass; - -} -std::vector* NIFLoader::getShapes(std::string lowername){ - - std::map,ciLessBoost>::iterator iter = allshapesmap.find(lowername); - std::vector* pass = 0; - if(iter != allshapesmap.end()) - pass = &(iter->second); - return pass; -} - -std::map* NIFLoader::getTextIndices(std::string lowername){ - std::map, ciLessBoost>::iterator iter = alltextmappings.find(lowername); - std::map* pass = 0; - if(iter != alltextmappings.end()) - pass = &(iter->second); - return pass; -} - - - - /* More code currently not in use, from the old D source. This was used in the first attempt at loading NIF meshes, where each submesh in the file was given a separate bone in a skeleton. Unfortunately diff --git a/components/nifogre/ogre_nif_loader.hpp b/components/nifogre/ogre_nif_loader.hpp index c6d7e7286..b6610d8a7 100644 --- a/components/nifogre/ogre_nif_loader.hpp +++ b/components/nifogre/ogre_nif_loader.hpp @@ -26,37 +26,25 @@ #include #include -#include -#include -#include -#include -#include -#include - -#include -#include "../nif/nif_file.hpp" -#include "../nif/node.hpp" -#include "../nif/data.hpp" -#include "../nif/property.hpp" -#include "../nif/controller.hpp" -#include "../nif/extra.hpp" -#include +#include #include -#include -// For warning messages -#include -#include -using namespace boost::algorithm; +#include +#include +#include +#include "../nif/node.hpp" + +#include class BoundsFinder; struct ciLessBoost : std::binary_function { - bool operator() (const std::string & s1, const std::string & s2) const { - //case insensitive version of is_less - return lexicographical_compare(s1, s2, is_iless()); + bool operator() (const std::string & s1, const std::string & s2) const + { + //case insensitive version of is_less + return boost::algorithm::lexicographical_compare(s1, s2, boost::algorithm::is_iless()); } }; @@ -65,138 +53,56 @@ namespace Nif class Node; class Transformation; class NiTriShape; - class Vector; - class Matrix; -} - -namespace Mangle -{ - namespace VFS - { - class OgreVFS; - } } namespace NifOgre { +// FIXME: These should not be in NifOgre, it works agnostic of what model format is used +typedef std::map TextKeyMap; +struct EntityList { + std::vector mEntities; + Ogre::Entity *mSkelBase; + + EntityList() : mSkelBase(0) + { } +}; + + +/** This holds a list of meshes along with the names of their parent nodes + */ +typedef std::vector< std::pair > MeshPairList; /** Manual resource loader for NIF meshes. This is the main class responsible for translating the internal NIF mesh structure into - something Ogre can use. Later it will also handle the insertion of - collision meshes into Bullet / OgreBullet. + something Ogre can use. You have to insert meshes manually into Ogre like this: NIFLoader::load("somemesh.nif"); - Afterwards, you can use the mesh name "somemesh.nif" normally to - create entities and so on. The mesh isn't loaded from disk until - OGRE needs it for rendering. Thus the above load() command is not - very resource intensive, and can safely be done for a large number - of meshes at load time. + This returns a list of meshes used by the model, as well as the names of + their parent nodes (as they pertain to the skeleton, which is optionally + returned in the second argument if it exists). */ -class NIFLoader : Ogre::ManualResourceLoader +class NIFLoader { - public: - static int numberOfMeshes; - static NIFLoader& getSingleton(); - static NIFLoader* getSingletonPtr(); + static MeshPairList load(std::string name, std::string skelName, TextKeyMap *textkeys, const std::string &group); - virtual void loadResource(Ogre::Resource *resource); - - static Ogre::MeshPtr load(const std::string &name, - const std::string &group="General"); - //void insertMeshInsideBase(Ogre::Mesh* mesh); - std::vector* getAnim(std::string name); - std::vector* getShapes(std::string name); - std::map* getTextIndices(std::string name); - - - Ogre::Vector3 convertVector3(const Nif::Vector& vec); - Ogre::Quaternion convertRotation(const Nif::Matrix& rot); - - void setOutputAnimFiles(bool output); - void setVerbosePath(std::string path); - - private: - - NIFLoader() : resourceName(""), resourceGroup("General"), flip(false), mNormaliseNormals(false), - mFlipVertexWinding(false), mOutputAnimFiles(false), inTheSkeletonTree(false) {} - NIFLoader(NIFLoader& n) {} - - void calculateTransform(); - - - void warn(std::string msg); - void fail(std::string msg); - - void handleNode( Nif::Node *node, int flags, - const Nif::Transformation *trafo, BoundsFinder &bounds, Ogre::Bone *parentBone, std::vector boneSequence); - - void handleNiTriShape(Nif::NiTriShape *shape, int flags, BoundsFinder &bounds, Nif::Transformation original, std::vector boneSequence); - - void createOgreSubMesh(Nif::NiTriShape *shape, const Ogre::String &material, std::list &vertexBoneAssignments); - - void createMaterial(const Ogre::String &name, - const Nif::Vector &ambient, - const Nif::Vector &diffuse, - const Nif::Vector &specular, - const Nif::Vector &emissive, - float glossiness, float alpha, - int alphaFlags, float alphaTest, - const Ogre::String &texName); - - void findRealTexture(Ogre::String &texName); - - Ogre::String getUniqueName(const Ogre::String &input); - - //returns the skeleton name of this mesh - std::string getSkeletonName() - { - return resourceName + ".skel"; - } - - // This is the interface to the Ogre resource system. It allows us to - // load NIFs from BSAs, in the file system and in any other place we - // tell Ogre to look (eg. in zip or rar files.) It's also used to - // check for the existence of texture files, so we can exchange the - // extension from .tga to .dds if the texture is missing. - Mangle::VFS::OgreVFS *vfs; - - std::string verbosePath; - std::string resourceName; - std::string resourceGroup; - Ogre::Matrix4 mTransform; - Ogre::AxisAlignedBox mBoundingBox; - bool flip; - bool mNormaliseNormals; - bool mFlipVertexWinding; - bool bNiTri; - bool mOutputAnimFiles; - std::multimap MaterialMap; - - // pointer to the ogre mesh which is currently build - Ogre::Mesh *mesh; - Ogre::SkeletonPtr mSkel; - Ogre::Vector3 vector; - std::vector shapes; - std::string resourcename; - std::string triname; - std::vector allanim; - - std::map textmappings; - std::map,ciLessBoost> alltextmappings; - std::map,ciLessBoost> allanimmap; - std::map,ciLessBoost> allshapesmap; - std::vector mAnim; - std::vector mS; - std::vector needBoneAssignments; - bool inTheSkeletonTree; - +public: + static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + const std::string &name, + const std::string &group="General"); + static EntityList createEntities(Ogre::SceneNode *parent, + TextKeyMap *textkeys, + const std::string &name, + const std::string &group="General"); }; } #endif + + diff --git a/components/nifogre/tests/ogre_common.cpp b/components/nifogre/tests/ogre_common.cpp index 949c91c4f..657913f30 100644 --- a/components/nifogre/tests/ogre_common.cpp +++ b/components/nifogre/tests/ogre_common.cpp @@ -1,6 +1,5 @@ #include #include -#include using namespace std; using namespace Ogre; diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 9b941e253..dd89dde65 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -66,6 +66,8 @@ void Manager::saveUser(const std::string& file) } fout << it->first.second << " = " << it->second << '\n'; } + + fout.close(); } const std::string Manager::getString (const std::string& setting, const std::string& category) diff --git a/components/terrain/esm_land_factory.cpp b/components/terrain/esm_land_factory.cpp index 315188234..a6335c6dc 100644 --- a/components/terrain/esm_land_factory.cpp +++ b/components/terrain/esm_land_factory.cpp @@ -8,41 +8,7 @@ using namespace Terrain; -static class ESMLandStream : public Mangle::Stream -{ -public: - ESMLandStream(ESM::Land *l, ESM::ESMReader &r) - { - } -}; - bool ESMLandFactory::has(int x, int y) { return store.landscapes.has(x,y); } - -LandDataPtr get(int x, int y, LandInfo &info) -{ - assert(has(x,y)); - - // Set up the info - info.grid = LGT_Quadratic; - info.data = LDT_Float; - - const float SIZE = 8192; // CHECK - - info.xsize = SIZE; - info.ysize = SIZE; - info.numx = 65; - info.numy = 65; - info.xoffset = SIZE*x; - info.yoffset = SIZE*y; - - // Get the Land struct from store - ESM::Land* land = store.landscapes.find(x,y); - assert(land->hasData); - - // Create a stream for the data and return it. - LandDataPtr ptr(new ESMLandStream(land, reader)); - return ptr; -} diff --git a/components/terrain/esm_land_factory.hpp b/components/terrain/esm_land_factory.hpp index 4fd95caa9..bb1f9a8c6 100644 --- a/components/terrain/esm_land_factory.hpp +++ b/components/terrain/esm_land_factory.hpp @@ -32,10 +32,6 @@ namespace Terrain // True if this factory has any data for the given grid cell. bool has(int x, int y); - - // Return stream to data for this cell. Additional data about the - // landscape is returned through the LandInfo struct. - LandDataPtr get(int x, int y, LandInfo &info); }; } #endif diff --git a/components/terrain/heightmapbuf.hpp b/components/terrain/heightmapbuf.hpp index 82154ce88..d147e6015 100644 --- a/components/terrain/heightmapbuf.hpp +++ b/components/terrain/heightmapbuf.hpp @@ -8,7 +8,7 @@ #include "heightmap.hpp" #include "land_factory.hpp" #include -#include +#include namespace Terrain { diff --git a/components/terrain/land_factory.hpp b/components/terrain/land_factory.hpp index f41946b49..c4d160443 100644 --- a/components/terrain/land_factory.hpp +++ b/components/terrain/land_factory.hpp @@ -1,8 +1,6 @@ #ifndef TERRAIN_LAND_FACTORY_H #define TERRAIN_LAND_FACTORY_H -#include - namespace Terrain { enum LandInfoGridType @@ -32,12 +30,6 @@ namespace Terrain float xoffset, yoffset; }; - /* We use normal streams for data. This allows us to just pass (for - example) a file stream as height map input later, with no extra - fuzz. - */ - typedef Mangle::Stream::StreamPtr LandDataPtr; - /* Factory class that provides streams to land data cells. Each "cell" has a unique integer coordinate in the plane. @@ -46,10 +38,6 @@ namespace Terrain { // True if this factory has any data for the given grid cell. virtual bool has(int x, int y) = 0; - - // Return stream to data for this cell. Additional data about the - // landscape is returned through the LandInfo struct. - virtual LandDataPtr get(int x, int y, LandInfo &info) = 0; }; } #endif diff --git a/components/terrain/triangulator.hpp b/components/terrain/triangulator.hpp index cedf0c6a2..c5c0e699b 100644 --- a/components/terrain/triangulator.hpp +++ b/components/terrain/triangulator.hpp @@ -28,7 +28,7 @@ terrains of the same size, once instance can usually be shared. */ -#include +#include namespace Terrain { diff --git a/components/to_utf8/gen_iconv.cpp b/components/to_utf8/gen_iconv.cpp index b7298e304..cc7cc191a 100644 --- a/components/to_utf8/gen_iconv.cpp +++ b/components/to_utf8/gen_iconv.cpp @@ -5,7 +5,7 @@ using namespace std; #include -#include +#include void tab() { cout << " "; } diff --git a/components/to_utf8/to_utf8.cpp b/components/to_utf8/to_utf8.cpp index 3fbbeb733..6bcbbd0e6 100644 --- a/components/to_utf8/to_utf8.cpp +++ b/components/to_utf8/to_utf8.cpp @@ -1,7 +1,7 @@ #include "to_utf8.hpp" #include -#include +#include /* This file contains the code to translate from WINDOWS-1252 (native charset used in English version of Morrowind) to UTF-8. The library diff --git a/credits.txt b/credits.txt new file mode 100644 index 000000000..c7ec4936e --- /dev/null +++ b/credits.txt @@ -0,0 +1,113 @@ +Contributors + +The OpenMW project was started in 2008 by Nicolay Korslund. +In the course of years many people have contributed to the project. + +If you feel your name is missing from this list, +please notify a developer. + + +Programmers: +Marc Zinnschlag (Zini) - Lead Programmer/Project Manager + +Aleksandar Jovanov +Alexander Olofsson (Ace) +Artem Kotsynyak (greye) +athile +BrotherBrick +Cris Mihalache (Mirceam) +Eli2 +gugus / gus +Jacob Essex (Yacoby) +Jannik Heller (scrawl) +Jason Hooks (jhooks) +Karl-Felix Glatzer (k1ll) +Lukasz Gromanowski (lgro) +Michael Mc Donnell +Michael Papageorgiou (werdanith) +Nikolay Kasyanov (corristo) +Pieter van der Kloet (pvdk) +Roman Melnik (Kromgart) +Sebastian Wick (swick) +Sylvain T. (Garvek) + + +Packagers: +Alexander Olofsson (Ace) - Windows +BrotherBrick - Ubuntu Linux +Edmondo Tommasina - Gentoo Linux +Kenny Armstrong (artorius) - Fedora Linux +Nikolay Kasyanov (corristo) - Mac OS X +Sandy Carter (bwrsandman) - Arch Linux + + +Public Relations: +ElderTroll - Release Manager +sir_herrbatka - News Writer +WeirdSexy - Podcaster + + +Website: +juanmnzsk8 - Spanish News Writer +Julien Voisin (jvoisin/ap0) - French News Writer +Kingpix - Italian News Writer +Lukasz Gromanowski (lgro) - Website Administrator +Nikolay Kasyanov (corristo) - Russian News Writer +Okulo - Dutch News Writer +penguinroad - Indonesian News Writer +Ryan Sardonic (Wry) - Wiki Editor +sir_herrbatka - Forum Admin/Polish News Writer +spyboot - German News Writer + + +Formula Research: +Epsilon +fragonard +Greendogo +HiPhish +modred11 +Myckel +natirips +Sadler + + +Artwork: +Necrod - OpenMW Logo +raevol - Wordpress Theme + + +Inactive Contributors: +Ardekantur +Armin Preiml +Diggory Hardy +Jan Borsodi +Jan-Peter Nilsson (peppe) +Josua Grawitter +Lordrea +Nicolay Korslund +sergoz +Star-Demon +Yuri Krupenin + + +Additional Credits: +In this section we would like to thank people not part of OpenMW for their work. + +Thanks to Maxim Nikolaev, +for allowing us to use his excellent Morrowind fan-art on our website and in other places. + +Thanks to DokterDume, +for kindly providing us with the Moon and Star logo, +used as the application icon and project logo. + +Thanks to Kevin Ryan, +for creating the icon used for the Data Files tab of the OpenMW Launcher. + +Thanks to Georg Duffner, +for the open-source EB Garamond fontface. + +Thanks to Dongle, +for his Daedric fontface, see Daedric Font License.txt for his license terms. + +Thanks to Bitstream Inc. +for their Bitstream Vera fontface, see Bitstream Vera License.txt for their license terms. diff --git a/extern/shiny b/extern/shiny new file mode 160000 index 000000000..164bc8d3b --- /dev/null +++ b/extern/shiny @@ -0,0 +1 @@ +Subproject commit 164bc8d3bfe860bd16ad89c0bd1b59f465c9bb24 diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 8ab3d5b51..3e99f5745 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -1,16 +1,50 @@ project(resources) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/caustic_0.png "${OpenMW_BINARY_DIR}/resources/water/caustic_0.png" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/underwater.cg "${OpenMW_BINARY_DIR}/resources/water/underwater.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/perlinvolume.dds "${OpenMW_BINARY_DIR}/resources/water/perlinvolume.dds" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.compositor "${OpenMW_BINARY_DIR}/resources/water/water.compositor" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.material "${OpenMW_BINARY_DIR}/resources/water/water.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/WaterNormal2.tga "${OpenMW_BINARY_DIR}/resources/water/WaterNormal2.tga" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/water/water.cg "${OpenMW_BINARY_DIR}/resources/water/water.cg" COPYONLY) +set(WATER_FILES + underwater_dome.mesh + water_nm.png +) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.cg "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.cg" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.material "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer/gbuffer.compositor "${OpenMW_BINARY_DIR}/resources/gbuffer/gbuffer.compositor" COPYONLY) +set(GBUFFER_FILES + gbuffer.compositor +) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/shadows/depthshadowcaster.material "${OpenMW_BINARY_DIR}/resources/shadows/depthshadowcaster.material" COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/shadows/depthshadowcaster.cg "${OpenMW_BINARY_DIR}/resources/shadows/depthshadowcaster.cg" COPYONLY) +set(MATERIAL_FILES + atmosphere.shader + atmosphere.shaderset + clouds.shader + clouds.shaderset + core.h + moon.shader + moon.shaderset + objects.mat + objects.shader + objects.shaderset + openmw.configuration + quad2.shader + quad.mat + quad.shader + quad.shaderset + shadowcaster.mat + shadowcaster.shader + shadowcaster.shaderset + shadows.h + sky.mat + stars.shader + stars.shaderset + sun.shader + sun.shaderset + terrain.shader + terrain.shaderset + underwater.h + water.mat + water.shader + water.shaderset + +) + +copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") + +copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/gbuffer "${OpenMW_BINARY_DIR}/resources/gbuffer/" "${GBUFFER_FILES}") + +copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/materials "${OpenMW_BINARY_DIR}/resources/materials/" "${MATERIAL_FILES}") diff --git a/files/gbuffer/gbuffer.cg b/files/gbuffer/gbuffer.cg deleted file mode 100644 index c7f2fe678..000000000 --- a/files/gbuffer/gbuffer.cg +++ /dev/null @@ -1,18 +0,0 @@ -void RenderScene_vs(in float4 position : POSITION - ,in float2 uv :TEXCOORD0 - ,uniform float4x4 wvp - ,out float4 oPosition : POSITION - ,out float2 oUV :TEXCOORD0) -{ - oPosition = mul(wvp, position); - oUV = uv; -} - -void RenderScene_ps(in float4 position : POSITION - ,in float2 uv :TEXCOORD0 - ,uniform sampler2D tex1 : TEXUNIT0 - ,out float4 oColor : COLOR) -{ - float4 scene =tex2D(tex1, uv); - oColor= scene; -} diff --git a/files/gbuffer/gbuffer.compositor b/files/gbuffer/gbuffer.compositor index 6ca35df87..04600ce9b 100644 --- a/files/gbuffer/gbuffer.compositor +++ b/files/gbuffer/gbuffer.compositor @@ -9,16 +9,21 @@ compositor gbuffer target mrt_output { input none + pass clear { - // make sure to set this to the viewport background color from outside colour_value 0 0 0 1 } + pass render_quad + { + // this makes sure the depth for background is set to 1 + material openmw_viewport_init + } pass render_scene { // Renders everything except water first_render_queue 0 - last_render_queue 70 + last_render_queue 50 } } @@ -29,7 +34,7 @@ compositor gbuffer pass render_quad { - material RenderScene + material quad input 0 mrt_output 0 } } @@ -61,12 +66,12 @@ compositor gbufferFinalizer } pass render_quad { - material RenderSceneNoDepth + material quad_noDepthWrite input 0 previousscene } pass render_scene { - first_render_queue 71 + first_render_queue 51 last_render_queue 100 } } @@ -78,7 +83,7 @@ compositor gbufferFinalizer } pass render_quad { - material RenderSceneNoDepth + material quad_noDepthWrite input 0 no_mrt_output } } diff --git a/files/gbuffer/gbuffer.material b/files/gbuffer/gbuffer.material deleted file mode 100644 index faa8dd498..000000000 --- a/files/gbuffer/gbuffer.material +++ /dev/null @@ -1,63 +0,0 @@ -vertex_program RenderGBuffer_vs cg -{ - source gbuffer.cg - profiles vs_4_0 vs_1_1 arbvp1 - entry_point RenderScene_vs - default_params - { - param_named_auto wvp worldviewproj_matrix - } -} -fragment_program RenderGBuffer_ps cg -{ - source gbuffer.cg - entry_point RenderScene_ps - profiles ps_4_0 ps_2_x arbfp1 - default_params - { - } -} -material RenderScene -{ - technique - { - pass - { - vertex_program_ref RenderGBuffer_vs - { - } - - fragment_program_ref RenderGBuffer_ps - { - } - - texture_unit tex1 - { - //scenebuffer - } - } - } -} - -material RenderSceneNoDepth -{ - technique - { - pass - { - depth_write off - vertex_program_ref RenderGBuffer_vs - { - } - - fragment_program_ref RenderGBuffer_ps - { - } - - texture_unit tex1 - { - //scenebuffer - } - } - } -} diff --git a/files/launcher.qss b/files/launcher.qss index 8be235f71..1eb056d4d 100644 --- a/files/launcher.qss +++ b/files/launcher.qss @@ -22,7 +22,8 @@ stop:0.9 rgba(0, 0, 0, 55), stop:1 rgba(0, 0, 0, 100)); - font: 26pt "EB Garamond"; + font-size: 26pt; + font-family: "EB Garamond", "EB Garamond 08"; color: black; border-right: 1px solid rgba(0, 0, 0, 155); @@ -54,7 +55,8 @@ } #ProfileLabel { - font: 18pt "EB Garamond"; + font-size: 18pt; + font-family: "EB Garamond", "EB Garamond 08"; } #ProfilesComboBox { @@ -82,7 +84,8 @@ padding-top: 3px; padding-left: 4px; - font: 12pt "EB Garamond"; + font-size: 12pt; + font-family: "EB Garamond", "EB Garamond 08"; } #ProfilesComboBox::drop-down { diff --git a/files/materials/atmosphere.shader b/files/materials/atmosphere.shader new file mode 100644 index 000000000..295fa9376 --- /dev/null +++ b/files/materials/atmosphere.shader @@ -0,0 +1,37 @@ +#include "core.h" + +#define MRT @shGlobalSettingBool(mrt_output) + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + + shColourInput(float4) + shOutput(float4, colourPassthrough) + + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + colourPassthrough = colour; + } + +#else + + SH_BEGIN_PROGRAM + shInput(float4, colourPassthrough) +#if MRT + shDeclareMrtOutput(1) +#endif + shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) + + SH_START_PROGRAM + { + shOutputColour(0) = colourPassthrough * atmosphereColour; + +#if MRT + shOutputColour(1) = float4(1,1,1,1); +#endif + } + +#endif diff --git a/files/materials/atmosphere.shaderset b/files/materials/atmosphere.shaderset new file mode 100644 index 000000000..54108dbba --- /dev/null +++ b/files/materials/atmosphere.shaderset @@ -0,0 +1,15 @@ +shader_set atmosphere_vertex +{ + source atmosphere.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set atmosphere_fragment +{ + source atmosphere.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/materials/clouds.shader b/files/materials/clouds.shader new file mode 100644 index 000000000..f4258bf5d --- /dev/null +++ b/files/materials/clouds.shader @@ -0,0 +1,52 @@ +#include "core.h" + +#define MRT @shGlobalSettingBool(mrt_output) + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shVertexInput(float2, uv0) + shOutput(float2, UV) + shColourInput(float4) + shOutput(float4, colourPassthrough) + + SH_START_PROGRAM + { + colourPassthrough = colour; + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + } + +#else + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shInput(float4, colourPassthrough) +#if MRT + shDeclareMrtOutput(1) +#endif + + shSampler2D(diffuseMap1) + shSampler2D(diffuseMap2) + + shUniform(float, cloudBlendFactor) @shSharedParameter(cloudBlendFactor) + shUniform(float, cloudAnimationTimer) @shSharedParameter(cloudAnimationTimer) + shUniform(float, cloudOpacity) @shSharedParameter(cloudOpacity) + shUniform(float3, cloudColour) @shSharedParameter(cloudColour) + + SH_START_PROGRAM + { + // Scroll in y direction + float2 scrolledUV = UV + float2(0,1) * cloudAnimationTimer * 0.003; + + float4 albedo = shSample(diffuseMap1, scrolledUV) * (1-cloudBlendFactor) + shSample(diffuseMap2, scrolledUV) * cloudBlendFactor; + + shOutputColour(0) = colourPassthrough * float4(cloudColour, 1) * albedo * float4(1,1,1, cloudOpacity); + +#if MRT + shOutputColour(1) = float4(1,1,1,1); +#endif + } + +#endif diff --git a/files/materials/clouds.shaderset b/files/materials/clouds.shaderset new file mode 100644 index 000000000..5fffb5658 --- /dev/null +++ b/files/materials/clouds.shaderset @@ -0,0 +1,15 @@ +shader_set clouds_vertex +{ + source clouds.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set clouds_fragment +{ + source clouds.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/materials/core.h b/files/materials/core.h new file mode 100644 index 000000000..cba716777 --- /dev/null +++ b/files/materials/core.h @@ -0,0 +1,168 @@ +#if SH_HLSL == 1 || SH_CG == 1 + + #define shTexture2D sampler2D + #define shSample(tex, coord) tex2D(tex, coord) + #define shCubicSample(tex, coord) texCUBE(tex, coord) + #define shLerp(a, b, t) lerp(a, b, t) + #define shSaturate(a) saturate(a) + + #define shSampler2D(name) , uniform sampler2D name : register(s@shCounter(0)) @shUseSampler(name) + + #define shSamplerCube(name) , uniform samplerCUBE name : register(s@shCounter(0)) @shUseSampler(name) + + #define shMatrixMult(m, v) mul(m, v) + + #define shUniform(type, name) , uniform type name + + #define shTangentInput(type) , in type tangent : TANGENT + #define shVertexInput(type, name) , in type name : TEXCOORD@shCounter(1) + #define shInput(type, name) , in type name : TEXCOORD@shCounter(1) + #define shOutput(type, name) , out type name : TEXCOORD@shCounter(2) + + #define shNormalInput(type) , in type normal : NORMAL + + #define shColourInput(type) , in type colour : COLOR + + #ifdef SH_VERTEX_SHADER + + #define shOutputPosition oPosition + #define shInputPosition iPosition + + + #define SH_BEGIN_PROGRAM \ + void main( \ + float4 iPosition : POSITION \ + , out float4 oPosition : POSITION + + #define SH_START_PROGRAM \ + ) \ + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shOutputColour(num) oColor##num + + #define shDeclareMrtOutput(num) , out float4 oColor##num : COLOR##num + + #define SH_BEGIN_PROGRAM \ + void main( \ + out float4 oColor0 : COLOR + + #define SH_START_PROGRAM \ + ) \ + + #endif + +#endif + +#if SH_GLSL == 1 + + @version 120 + + #define float2 vec2 + #define float3 vec3 + #define float4 vec4 + #define int2 ivec2 + #define int3 ivec3 + #define int4 ivec4 + #define shTexture2D sampler2D + #define shSample(tex, coord) texture2D(tex, coord) + #define shCubicSample(tex, coord) textureCube(tex, coord) + #define shLerp(a, b, t) mix(a, b, t) + #define shSaturate(a) clamp(a, 0.0, 1.0) + + #define shUniform(type, name) uniform type name; + + #define shSampler2D(name) uniform sampler2D name; @shUseSampler(name) + + #define shSamplerCube(name) uniform samplerCube name; @shUseSampler(name) + + #define shMatrixMult(m, v) (m * v) + + #define shOutputPosition gl_Position + + #define float4x4 mat4 + #define float3x3 mat3 + + // GLSL 1.3 + #if 0 + + // automatically recognized by ogre when the input name equals this + #define shInputPosition vertex + + #define shOutputColour(num) oColor##num + + #define shTangentInput(type) in type tangent; + #define shVertexInput(type, name) in type name; + #define shInput(type, name) in type name; + #define shOutput(type, name) out type name; + + // automatically recognized by ogre when the input name equals this + #define shNormalInput(type) in type normal; + #define shColourInput(type) in type colour; + + #ifdef SH_VERTEX_SHADER + + #define SH_BEGIN_PROGRAM \ + in float4 vertex; + #define SH_START_PROGRAM \ + void main(void) + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shDeclareMrtOutput(num) out vec4 oColor##num; + + #define SH_BEGIN_PROGRAM \ + out float4 oColor0; + #define SH_START_PROGRAM \ + void main(void) + + + #endif + + #endif + + // GLSL 1.2 + + #if 1 + + // automatically recognized by ogre when the input name equals this + #define shInputPosition vertex + + #define shOutputColour(num) gl_FragData[num] + + #define shTangentInput(type) attribute type tangent; + #define shVertexInput(type, name) attribute type name; + #define shInput(type, name) varying type name; + #define shOutput(type, name) varying type name; + + // automatically recognized by ogre when the input name equals this + #define shNormalInput(type) attribute type normal; + #define shColourInput(type) attribute type colour; + + #ifdef SH_VERTEX_SHADER + + #define SH_BEGIN_PROGRAM \ + attribute vec4 vertex; + #define SH_START_PROGRAM \ + void main(void) + + #endif + + #ifdef SH_FRAGMENT_SHADER + + #define shDeclareMrtOutput(num) + + #define SH_BEGIN_PROGRAM + + #define SH_START_PROGRAM \ + void main(void) + + + #endif + + #endif +#endif diff --git a/files/materials/moon.shader b/files/materials/moon.shader new file mode 100644 index 000000000..02f3d8001 --- /dev/null +++ b/files/materials/moon.shader @@ -0,0 +1,51 @@ +#include "core.h" + +#define MRT @shGlobalSettingBool(mrt_output) + + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shVertexInput(float2, uv0) + shOutput(float2, UV) + + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + } + +#else + + SH_BEGIN_PROGRAM + shSampler2D(diffuseMap) + shSampler2D(alphaMap) + shInput(float2, UV) +#if MRT + shDeclareMrtOutput(1) +#endif + shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) + shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + + shUniform(float4, atmosphereColour) @shSharedParameter(atmosphereColour) + + SH_START_PROGRAM + { + + float4 tex = shSample(diffuseMap, UV); + + shOutputColour(0) = float4(materialEmissive.xyz, 1) * tex; + + shOutputColour(0).a = shSample(alphaMap, UV).a * materialDiffuse.a; + + shOutputColour(0).rgb += (1-tex.a) * shOutputColour(0).a * atmosphereColour.rgb; //fill dark side of moon with atmosphereColour + shOutputColour(0).rgb += (1-materialDiffuse.a) * atmosphereColour.rgb; //fade bump + +#if MRT + shOutputColour(1) = float4(1,1,1,1); +#endif + + } + +#endif diff --git a/files/materials/moon.shaderset b/files/materials/moon.shaderset new file mode 100644 index 000000000..659481a96 --- /dev/null +++ b/files/materials/moon.shaderset @@ -0,0 +1,15 @@ +shader_set moon_vertex +{ + source moon.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set moon_fragment +{ + source moon.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/materials/objects.mat b/files/materials/objects.mat new file mode 100644 index 000000000..f1198b4a2 --- /dev/null +++ b/files/materials/objects.mat @@ -0,0 +1,67 @@ +material openmw_objects_base +{ + diffuse 1.0 1.0 1.0 1.0 + specular 0.4 0.4 0.4 32 + ambient 1.0 1.0 1.0 + emissive 0.0 0.0 0.0 + has_vertex_colour false + diffuseMap black.png + + is_transparent false // real transparency, alpha rejection doesn't count here + scene_blend default + depth_write default + alpha_rejection default + + pass + { + vertex_program openmw_objects_vertex + fragment_program openmw_objects_fragment + + shader_properties + { + has_vertex_colour $has_vertex_colour + is_transparent $is_transparent + } + + diffuse $diffuse + specular $specular + ambient $ambient + emissive $emissive + scene_blend $scene_blend + alpha_rejection $alpha_rejection + depth_write $depth_write + + ffp_vertex_colour_ambient $has_vertex_colour + + + texture_unit diffuseMap + { + direct_texture $diffuseMap + create_in_ffp true + } + + texture_unit shadowMap0 + { + content_type shadow + tex_address_mode clamp + filtering none + } + texture_unit shadowMap1 + { + content_type shadow + tex_address_mode clamp + filtering none + } + texture_unit shadowMap2 + { + content_type shadow + tex_address_mode clamp + filtering none + } + + texture_unit causticMap + { + direct_texture water_nm.png + } + } +} diff --git a/files/materials/objects.shader b/files/materials/objects.shader new file mode 100644 index 000000000..8e5cbf76e --- /dev/null +++ b/files/materials/objects.shader @@ -0,0 +1,301 @@ +#include "core.h" + + +#define FOG @shGlobalSettingBool(fog) +#define MRT @shPropertyNotBool(is_transparent) && @shGlobalSettingBool(mrt_output) +#define LIGHTING @shGlobalSettingBool(lighting) + +#define SHADOWS_PSSM LIGHTING && @shGlobalSettingBool(shadows_pssm) +#define SHADOWS LIGHTING && @shGlobalSettingBool(shadows) + +#if SHADOWS || SHADOWS_PSSM + #include "shadows.h" +#endif + +#if FOG || MRT || SHADOWS_PSSM +#define NEED_DEPTH +#endif + + +#define UNDERWATER @shGlobalSettingBool(underwater_effects) && LIGHTING + + +#define HAS_VERTEXCOLOR @shPropertyBool(has_vertex_colour) + +#ifdef SH_VERTEX_SHADER + + // ------------------------------------- VERTEX --------------------------------------- + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shVertexInput(float2, uv0) + shOutput(float2, UV) + shNormalInput(float4) +#ifdef NEED_DEPTH + shOutput(float, depthPassthrough) +#endif + +#if LIGHTING + shOutput(float3, normalPassthrough) + shOutput(float3, objSpacePositionPassthrough) +#endif + +#if HAS_VERTEXCOLOR + shColourInput(float4) + shOutput(float4, colourPassthrough) +#endif + +#if SHADOWS + shOutput(float4, lightSpacePos0) + shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif + +#if SHADOWS_PSSM + @shForeach(3) + shOutput(float4, lightSpacePos@shIterator) + shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) + @shEndForeach + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; +#if LIGHTING + normalPassthrough = normal.xyz; +#endif + +#ifdef NEED_DEPTH + depthPassthrough = shOutputPosition.z; +#endif + +#if LIGHTING + objSpacePositionPassthrough = shInputPosition.xyz; +#endif + +#if HAS_VERTEXCOLOR + colourPassthrough = colour; +#endif + +#if SHADOWS + lightSpacePos0 = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); +#endif +#if SHADOWS_PSSM + float4 wPos = shMatrixMult(worldMatrix, shInputPosition); + @shForeach(3) + lightSpacePos@shIterator = shMatrixMult(texViewProjMatrix@shIterator, wPos); + @shEndForeach +#endif + } + +#else + + // ----------------------------------- FRAGMENT ------------------------------------------ + +#if UNDERWATER + #include "underwater.h" +#endif + + SH_BEGIN_PROGRAM + shSampler2D(diffuseMap) + shInput(float2, UV) +#if MRT + shDeclareMrtOutput(1) +#endif + +#ifdef NEED_DEPTH + shInput(float, depthPassthrough) +#endif + +#if MRT + shUniform(float, far) @shAutoConstant(far, far_clip_distance) +#endif + +#if LIGHTING + shInput(float3, normalPassthrough) + shInput(float3, objSpacePositionPassthrough) + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) + #if !HAS_VERTEXCOLOR + shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) + #endif + shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) + shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + @shForeach(@shGlobalSettingString(num_lights)) + shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) + shUniform(float4, lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) + shUniform(float4, lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) + @shEndForeach +#endif + +#if FOG + shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) + shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) +#endif + +#if HAS_VERTEXCOLOR + shInput(float4, colourPassthrough) +#endif + +#if SHADOWS + shInput(float4, lightSpacePos0) + shSampler2D(shadowMap0) + shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, 1) +#endif +#if SHADOWS_PSSM + @shForeach(3) + shInput(float4, lightSpacePos@shIterator) + shSampler2D(shadowMap@shIterator) + shUniform(float2, invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator(1)) + @shEndForeach + shUniform(float3, pssmSplitPoints) @shSharedParameter(pssmSplitPoints) +#endif + +#if SHADOWS || SHADOWS_PSSM + shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) +#endif + +#if UNDERWATER + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) + shUniform(float, waterLevel) @shSharedParameter(waterLevel) + shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) + shUniform(float4, lightDirectionWS0) @shAutoConstant(lightDirectionWS0, light_position, 0) + + shSampler2D(causticMap) + + shUniform(float, waterTimer) @shSharedParameter(waterTimer) + shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) + shUniform(float, waterEnabled) @shSharedParameter(waterEnabled) + + shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) +#endif + + SH_START_PROGRAM + { + shOutputColour(0) = shSample(diffuseMap, UV); + +#if LIGHTING + float3 normal = normalize(normalPassthrough); + float3 lightDir; + float3 diffuse = float3(0,0,0); + float d; + +#if HAS_VERTEXCOLOR + // ambient vertex colour tracking, FFP behaviour + float3 ambient = colourPassthrough.xyz * lightAmbient.xyz; +#else + float3 ambient = materialAmbient.xyz * lightAmbient.xyz; +#endif + + // shadows only for the first (directional) light +#if SHADOWS + float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); +#endif +#if SHADOWS_PSSM + float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depthPassthrough, pssmSplitPoints); +#endif + +#if SHADOWS || SHADOWS_PSSM + float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; + float fade = 1-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); + shadow = (depthPassthrough > shadowFar_fadeStart.x) ? 1.0 : ((depthPassthrough > shadowFar_fadeStart.y) ? 1.0-((1.0-shadow)*fade) : shadow); +#endif + +#if !SHADOWS && !SHADOWS_PSSM + float shadow = 1.0; +#endif + + + + float3 caustics = float3(1,1,1); +#if UNDERWATER + float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePositionPassthrough,1)).xyz; + float3 waterEyePos = float3(1,1,1); + // NOTE: this calculation would be wrong for non-uniform scaling + float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); + waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); + caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); + if (worldPos.y >= waterLevel || waterEnabled != 1) + caustics = float3(1,1,1); +#endif + + + @shForeach(@shGlobalSettingString(num_lights)) + + /// \todo use the array auto params for lights, and use a real for-loop with auto param "light_count" iterations + lightDir = lightPosObjSpace@shIterator.xyz - (objSpacePositionPassthrough.xyz * lightPosObjSpace@shIterator.w); + d = length(lightDir); + + lightDir = normalize(lightDir); + +#if @shIterator == 0 + + #if (SHADOWS || SHADOWS_PSSM) + diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow * caustics; + + #else + diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * caustics; + + #endif + +#else + diffuse += materialDiffuse.xyz * lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0); +#endif + + @shEndForeach + + shOutputColour(0).xyz *= (ambient + diffuse + materialEmissive.xyz); +#endif + + +#if HAS_VERTEXCOLOR && !LIGHTING + shOutputColour(0).xyz *= colourPassthrough.xyz; +#endif + +#if FOG + float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); + + #if UNDERWATER + // regular fog only if fragment is above water + if (worldPos.y > waterLevel) + #endif + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); +#endif + + // prevent negative colour output (for example with negative lights) + shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); + +#if UNDERWATER + float fogAmount = (cameraPos.y > waterLevel) + ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) + : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); + + float3 eyeVec = normalize(cameraPos.xyz-worldPos); + + float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); + waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); + float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; + + float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); + waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); + float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; + float3 waterext = float3(0.6, 0.9, 1.0);//water extinction + watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); + watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; + + + float darkness = VISIBILITY*2.0; + darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); + watercolour *= darkness; + + float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); +#endif + +#if MRT + shOutputColour(1) = float4(depthPassthrough / far,1,1,1); +#endif + + } + +#endif diff --git a/files/materials/objects.shaderset b/files/materials/objects.shaderset new file mode 100644 index 000000000..028c15ce8 --- /dev/null +++ b/files/materials/objects.shaderset @@ -0,0 +1,15 @@ +shader_set openmw_objects_vertex +{ + source objects.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_3_0 vs_2_0 +} + +shader_set openmw_objects_fragment +{ + source objects.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} diff --git a/files/materials/openmw.configuration b/files/materials/openmw.configuration new file mode 100644 index 000000000..ee97451d3 --- /dev/null +++ b/files/materials/openmw.configuration @@ -0,0 +1,17 @@ +configuration water_reflection +{ + fog false + shadows false + shadows_pssm false + mrt_output false +} + +configuration local_map +{ + fog false + mrt_output false + lighting false + shadows false + shadows_pssm false + simple_water true +} diff --git a/files/materials/quad.mat b/files/materials/quad.mat new file mode 100644 index 000000000..afb7f5111 --- /dev/null +++ b/files/materials/quad.mat @@ -0,0 +1,35 @@ +material quad +{ + depth_write on + + pass + { + vertex_program quad_vertex + fragment_program quad_fragment + + depth_write $depth_write + + texture_unit SceneBuffer + { + } + } +} + +material quad_noDepthWrite +{ + parent quad + depth_write off +} + +material openmw_viewport_init +{ + pass + { + vertex_program viewport_init_vertex + fragment_program viewport_init_fragment + + depth_write off + depth_check off + scene_blend add + } +} diff --git a/files/materials/quad.shader b/files/materials/quad.shader new file mode 100644 index 000000000..4620588c3 --- /dev/null +++ b/files/materials/quad.shader @@ -0,0 +1,25 @@ +#include "core.h" + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shVertexInput(float2, uv0) + shOutput(float2, UV) + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + } + +#else + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shSampler2D(SceneBuffer) + SH_START_PROGRAM + { + shOutputColour(0) = shSample(SceneBuffer, UV); + } + +#endif diff --git a/files/materials/quad.shaderset b/files/materials/quad.shaderset new file mode 100644 index 000000000..c61497503 --- /dev/null +++ b/files/materials/quad.shaderset @@ -0,0 +1,31 @@ +shader_set quad_vertex +{ + source quad.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set quad_fragment +{ + source quad.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 + profiles_hlsl ps_2_0 +} + +shader_set viewport_init_vertex +{ + source quad2.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set viewport_init_fragment +{ + source quad2.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/materials/quad2.shader b/files/materials/quad2.shader new file mode 100644 index 000000000..e54d83ef4 --- /dev/null +++ b/files/materials/quad2.shader @@ -0,0 +1,23 @@ +#include "core.h" + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + } + +#else + + SH_BEGIN_PROGRAM + shUniform(float3, viewportBackground) @shSharedParameter(viewportBackground) + shDeclareMrtOutput(1) + SH_START_PROGRAM + { + shOutputColour(0) = float4(viewportBackground, 1); + shOutputColour(1) = float4(1,1,1,1); + } + +#endif diff --git a/files/materials/shadowcaster.mat b/files/materials/shadowcaster.mat new file mode 100644 index 000000000..5c5c8e088 --- /dev/null +++ b/files/materials/shadowcaster.mat @@ -0,0 +1,35 @@ +material openmw_shadowcaster_default +{ + create_configuration Default + allow_fixed_function false + pass + { + fog_override true + + vertex_program openmw_shadowcaster_vertex + fragment_program openmw_shadowcaster_fragment + + shader_properties + { + shadow_transparency true + } + } +} + +material openmw_shadowcaster_noalpha +{ + create_configuration Default + allow_fixed_function false + pass + { + fog_override true + + vertex_program openmw_shadowcaster_vertex + fragment_program openmw_shadowcaster_fragment + + shader_properties + { + shadow_transparency false + } + } +} diff --git a/files/materials/shadowcaster.shader b/files/materials/shadowcaster.shader new file mode 100644 index 000000000..b312d414c --- /dev/null +++ b/files/materials/shadowcaster.shader @@ -0,0 +1,56 @@ +#include "core.h" + +#define ALPHA @shPropertyBool(shadow_transparency) + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM +#if ALPHA + shVertexInput(float2, uv0) + shOutput(float2, UV) +#endif + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shOutput(float2, depth) + SH_START_PROGRAM + { + // this is the view space position + shOutputPosition = shMatrixMult(wvp, shInputPosition); + + // depth info for the fragment. + depth.x = shOutputPosition.z; + depth.y = shOutputPosition.w; + + // clamp z to zero. seem to do the trick. :-/ + shOutputPosition.z = max(shOutputPosition.z, 0); + +#if ALPHA + UV = uv0; +#endif + } + +#else + + SH_BEGIN_PROGRAM +#if ALPHA + shInput(float2, UV) + shSampler2D(texture1) +#endif + shInput(float2, depth) + SH_START_PROGRAM + { + float finalDepth = depth.x / depth.y; + + +#if ALPHA + // use alpha channel of the first texture + float alpha = shSample(texture1, UV).a; + + // discard if alpha is less than 0.5 + if (alpha < 1.0) + discard; +#endif + + shOutputColour(0) = float4(finalDepth, finalDepth, finalDepth, 1); + } + +#endif diff --git a/files/materials/shadowcaster.shaderset b/files/materials/shadowcaster.shaderset new file mode 100644 index 000000000..5f4990ed1 --- /dev/null +++ b/files/materials/shadowcaster.shaderset @@ -0,0 +1,15 @@ +shader_set openmw_shadowcaster_vertex +{ + source shadowcaster.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set openmw_shadowcaster_fragment +{ + source shadowcaster.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/materials/shadows.h b/files/materials/shadows.h new file mode 100644 index 000000000..65dffe492 --- /dev/null +++ b/files/materials/shadows.h @@ -0,0 +1,51 @@ + +#define FIXED_BIAS 0.0003 + +float depthShadowPCF (shTexture2D shadowMap, float4 shadowMapPos, float2 offset) +{ + shadowMapPos /= shadowMapPos.w; + float3 o = float3(offset.xy, -offset.x) * 0.3; + //float3 o = float3(0,0,0); + float c = (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.xy).r) ? 1 : 0; // top left + c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.xy).r) ? 1 : 0; // bottom right + c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy + o.zy).r) ? 1 : 0; // bottom left + c += (shadowMapPos.z <= FIXED_BIAS + shSample(shadowMap, shadowMapPos.xy - o.zy).r) ? 1 : 0; // top right + return c / 4; +} + + + +float pssmDepthShadow ( + + + float4 lightSpacePos0, + float2 invShadowmapSize0, + shTexture2D shadowMap0, + + float4 lightSpacePos1, + float2 invShadowmapSize1, + shTexture2D shadowMap1, + + float4 lightSpacePos2, + float2 invShadowmapSize2, + shTexture2D shadowMap2, + + float depth, + float3 pssmSplitPoints) + +{ + float shadow; + + float pcf1 = depthShadowPCF(shadowMap0, lightSpacePos0, invShadowmapSize0); + float pcf2 = depthShadowPCF(shadowMap1, lightSpacePos1, invShadowmapSize1); + float pcf3 = depthShadowPCF(shadowMap2, lightSpacePos2, invShadowmapSize2); + + if (depth < pssmSplitPoints.x) + shadow = pcf1; + else if (depth < pssmSplitPoints.y) + shadow = pcf2; + else + shadow = pcf3; + + return shadow; +} diff --git a/files/materials/sky.mat b/files/materials/sky.mat new file mode 100644 index 000000000..4af90a170 --- /dev/null +++ b/files/materials/sky.mat @@ -0,0 +1,108 @@ +material openmw_moon +{ + allow_fixed_function false + pass + { + vertex_program moon_vertex + fragment_program moon_fragment + + polygon_mode_overrideable off + depth_write off + depth_check off + scene_blend alpha_blend + + texture_unit diffuseMap + { + texture_alias $texture + } + + texture_unit alphaMap + { + direct_texture textures\tx_secunda_full.dds + } + } +} + +material openmw_clouds +{ + allow_fixed_function false + pass + { + vertex_program clouds_vertex + fragment_program clouds_fragment + + polygon_mode_overrideable off + + scene_blend alpha_blend + depth_write off + + // second diffuse map is used for weather transitions + texture_unit diffuseMap1 + { + texture_alias cloud_texture_1 + } + + texture_unit diffuseMap2 + { + texture_alias cloud_texture_2 + } + } +} + +material openmw_atmosphere +{ + allow_fixed_function false + pass + { + vertex_program atmosphere_vertex + fragment_program atmosphere_fragment + + polygon_mode_overrideable off + + scene_blend alpha_blend + depth_write off + } +} + +material openmw_stars +{ + allow_fixed_function false + pass + { + vertex_program stars_vertex + fragment_program stars_fragment + + polygon_mode_overrideable off + + depth_check off + depth_write off + scene_blend alpha_blend + + texture_unit diffuseMap + { + direct_texture $texture + } + } +} + +// used for both sun and sun glare +material openmw_sun +{ + allow_fixed_function false + pass + { + vertex_program sun_vertex + fragment_program sun_fragment + + polygon_mode_overrideable off + + depth_check off + depth_write off + scene_blend alpha_blend + + texture_unit diffuseMap + { + direct_texture $texture + } + } +} diff --git a/files/materials/stars.shader b/files/materials/stars.shader new file mode 100644 index 000000000..5a55d171e --- /dev/null +++ b/files/materials/stars.shader @@ -0,0 +1,46 @@ +#include "core.h" + +#define MRT @shGlobalSettingBool(mrt_output) + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + + shVertexInput(float2, uv0) + shOutput(float2, UV) + shOutput(float, fade) + + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + + fade = (shInputPosition.z > 50) ? 1 : 0; + } + +#else + + SH_BEGIN_PROGRAM +#if MRT + shDeclareMrtOutput(1) +#endif + + shInput(float2, UV) + shInput(float, fade) + + shSampler2D(diffuseMap) + shUniform(float, nightFade) @shSharedParameter(nightFade) + + + SH_START_PROGRAM + { + shOutputColour(0) = shSample(diffuseMap, UV) * float4(1,1,1, nightFade * fade); + + +#if MRT + shOutputColour(1) = float4(1,1,1,1); +#endif + } + +#endif diff --git a/files/materials/stars.shaderset b/files/materials/stars.shaderset new file mode 100644 index 000000000..0f8803450 --- /dev/null +++ b/files/materials/stars.shaderset @@ -0,0 +1,15 @@ +shader_set stars_vertex +{ + source stars.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set stars_fragment +{ + source stars.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/materials/sun.shader b/files/materials/sun.shader new file mode 100644 index 000000000..45cd2f24b --- /dev/null +++ b/files/materials/sun.shader @@ -0,0 +1,39 @@ +#include "core.h" + +#define MRT @shGlobalSettingBool(mrt_output) + + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shVertexInput(float2, uv0) + shOutput(float2, UV) + + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + } + +#else + + SH_BEGIN_PROGRAM + shSampler2D(diffuseMap) + shInput(float2, UV) +#if MRT + shDeclareMrtOutput(1) +#endif + shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) + //shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + + SH_START_PROGRAM + { + shOutputColour(0) = float4(1,1,1,materialDiffuse.a) * shSample(diffuseMap, UV); + +#if MRT + shOutputColour(1) = float4(1,1,1,1); +#endif + } + +#endif diff --git a/files/materials/sun.shaderset b/files/materials/sun.shaderset new file mode 100644 index 000000000..1b9e92a43 --- /dev/null +++ b/files/materials/sun.shaderset @@ -0,0 +1,15 @@ +shader_set sun_vertex +{ + source sun.shader + type vertex + profiles_cg vs_2_0 arbvp1 + profiles_hlsl vs_2_0 +} + +shader_set sun_fragment +{ + source sun.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps arbfp1 + profiles_hlsl ps_2_0 +} diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader new file mode 100644 index 000000000..7ef26d035 --- /dev/null +++ b/files/materials/terrain.shader @@ -0,0 +1,378 @@ +#include "core.h" + +#define IS_FIRST_PASS 1 + +#define FOG @shGlobalSettingBool(fog) +#define MRT @shGlobalSettingBool(mrt_output) + +#define LIGHTING @shGlobalSettingBool(lighting) + +#define SHADOWS_PSSM LIGHTING && @shGlobalSettingBool(shadows_pssm) +#define SHADOWS LIGHTING && @shGlobalSettingBool(shadows) + +#if SHADOWS || SHADOWS_PSSM +#include "shadows.h" +#endif + +#define COLOUR_MAP @shPropertyBool(colour_map) + +#define NUM_LAYERS @shPropertyString(num_layers) + +#if MRT || FOG || SHADOWS_PSSM +#define NEED_DEPTH 1 +#endif + +#define UNDERWATER @shGlobalSettingBool(underwater_effects) && LIGHTING + + +#if NEED_DEPTH +@shAllocatePassthrough(1, depth) +#endif + +@shAllocatePassthrough(2, UV) + +#if LIGHTING +@shAllocatePassthrough(3, objSpacePosition) +#endif + +#if SHADOWS +@shAllocatePassthrough(4, lightSpacePos0) +#endif +#if SHADOWS_PSSM +@shForeach(3) + @shAllocatePassthrough(4, lightSpacePos@shIterator) +@shEndForeach +#endif + +#ifdef SH_VERTEX_SHADER + + // ------------------------------------- VERTEX --------------------------------------- + + SH_BEGIN_PROGRAM + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) + shUniform(float4x4, viewProjMatrix) @shAutoConstant(viewProjMatrix, viewproj_matrix) + + shUniform(float2, lodMorph) @shAutoConstant(lodMorph, custom, 1001) + + shVertexInput(float2, uv0) + shVertexInput(float2, uv1) // lodDelta, lodThreshold + +#if SHADOWS + shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) +#endif + +#if SHADOWS_PSSM + @shForeach(3) + shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) + @shEndForeach +#endif + + + @shPassthroughVertexOutputs + + SH_START_PROGRAM + { + + + float4 worldPos = shMatrixMult(worldMatrix, shInputPosition); + + // determine whether to apply the LOD morph to this vertex + // we store the deltas against all vertices so we only want to apply + // the morph to the ones which would disappear. The target LOD which is + // being morphed to is stored in lodMorph.y, and the LOD at which + // the vertex should be morphed is stored in uv.w. If we subtract + // the former from the latter, and arrange to only morph if the + // result is negative (it will only be -1 in fact, since after that + // the vertex will never be indexed), we will achieve our aim. + // sign(vertexLOD - targetLOD) == -1 is to morph + float toMorph = -min(0, sign(uv1.y - lodMorph.y)); + + // morph + // this assumes XZ terrain alignment + worldPos.y += uv1.x * toMorph * lodMorph.x; + + + shOutputPosition = shMatrixMult(viewProjMatrix, worldPos); + +#if NEED_DEPTH + @shPassthroughAssign(depth, shOutputPosition.z); +#endif + + @shPassthroughAssign(UV, uv0); + +#if LIGHTING + @shPassthroughAssign(objSpacePosition, shInputPosition.xyz); +#endif + +#if SHADOWS + float4 lightSpacePos = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); + @shPassthroughAssign(lightSpacePos0, lightSpacePos); +#endif +#if SHADOWS_PSSM + float4 wPos = shMatrixMult(worldMatrix, shInputPosition); + + float4 lightSpacePos; + @shForeach(3) + lightSpacePos = shMatrixMult(texViewProjMatrix@shIterator, wPos); + @shPassthroughAssign(lightSpacePos@shIterator, lightSpacePos); + @shEndForeach +#endif + + } + +#else + + // ----------------------------------- FRAGMENT ------------------------------------------ + +#if UNDERWATER + #include "underwater.h" +#endif + + SH_BEGIN_PROGRAM + + +#if COLOUR_MAP + shSampler2D(colourMap) +#endif + + shSampler2D(normalMap) // global normal map + + +@shForeach(@shPropertyString(num_blendmaps)) + shSampler2D(blendMap@shIterator) +@shEndForeach + +@shForeach(@shPropertyString(num_layers)) + shSampler2D(diffuseMap@shIterator) +@shEndForeach + +#if FOG + shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) + shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) +#endif + + @shPassthroughFragmentInputs + +#if MRT + shDeclareMrtOutput(1) + shUniform(float, far) @shAutoConstant(far, far_clip_distance) +#endif + + +#if LIGHTING + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) + @shForeach(@shGlobalSettingString(terrain_num_lights)) + shUniform(float4, lightPosObjSpace@shIterator) @shAutoConstant(lightPosObjSpace@shIterator, light_position_object_space, @shIterator) + shUniform(float4, lightAttenuation@shIterator) @shAutoConstant(lightAttenuation@shIterator, light_attenuation, @shIterator) + shUniform(float4, lightDiffuse@shIterator) @shAutoConstant(lightDiffuse@shIterator, light_diffuse_colour, @shIterator) + @shEndForeach +#endif + + +#if SHADOWS + shSampler2D(shadowMap0) + shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, @shPropertyString(shadowtexture_offset)) +#endif +#if SHADOWS_PSSM + @shForeach(3) + shSampler2D(shadowMap@shIterator) + shUniform(float2, invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator(@shPropertyString(shadowtexture_offset))) + @shEndForeach + shUniform(float3, pssmSplitPoints) @shSharedParameter(pssmSplitPoints) +#endif + +#if SHADOWS || SHADOWS_PSSM + shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) +#endif + + +#if UNDERWATER + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) + shUniform(float, waterLevel) @shSharedParameter(waterLevel) + shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) + shUniform(float4, lightDirectionWS0) @shAutoConstant(lightDirectionWS0, light_position, 0) + + shSampler2D(causticMap) + + shUniform(float, waterTimer) @shSharedParameter(waterTimer) + shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) + + shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) +#endif + + + SH_START_PROGRAM + { + +#if NEED_DEPTH + float depth = @shPassthroughReceive(depth); +#endif + + float2 UV = @shPassthroughReceive(UV); + +#if LIGHTING + float3 objSpacePosition = @shPassthroughReceive(objSpacePosition); + + float3 normal = shSample(normalMap, UV).rgb * 2 - 1; + normal = normalize(normal); +#endif + + + + float3 caustics = float3(1,1,1); +#if UNDERWATER + + float3 worldPos = shMatrixMult(worldMatrix, float4(objSpacePosition,1)).xyz; + float3 waterEyePos = float3(1,1,1); + // NOTE: this calculation would be wrong for non-uniform scaling + float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0)); + waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel); + caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed); + if (worldPos.y >= waterLevel) + caustics = float3(1,1,1); + + + +#endif + + + // Layer calculations +@shForeach(@shPropertyString(num_blendmaps)) + float4 blendValues@shIterator = shSample(blendMap@shIterator, UV); +@shEndForeach + + float3 albedo = float3(0,0,0); +@shForeach(@shPropertyString(num_layers)) + + +#if IS_FIRST_PASS == 1 && @shIterator == 0 + // first layer of first pass doesn't need a blend map + albedo = shSample(diffuseMap0, UV * 10).rgb; +#else + albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); + +#endif +@shEndForeach + + shOutputColour(0) = float4(1,1,1,1); + +#if COLOUR_MAP + shOutputColour(0).rgb *= shSample(colourMap, UV).rgb; +#endif + + shOutputColour(0).rgb *= albedo; + + + + + + + // Lighting + +#if LIGHTING + // shadows only for the first (directional) light +#if SHADOWS + float4 lightSpacePos0 = @shPassthroughReceive(lightSpacePos0); + float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); +#endif +#if SHADOWS_PSSM + @shForeach(3) + float4 lightSpacePos@shIterator = @shPassthroughReceive(lightSpacePos@shIterator); + @shEndForeach + + float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depth, pssmSplitPoints); +#endif + +#if SHADOWS || SHADOWS_PSSM + float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; + float fade = 1-((depth - shadowFar_fadeStart.y) / fadeRange); + shadow = (depth > shadowFar_fadeStart.x) ? 1.0 : ((depth > shadowFar_fadeStart.y) ? 1.0-((1.0-shadow)*fade) : shadow); +#endif + +#if !SHADOWS && !SHADOWS_PSSM + float shadow = 1.0; +#endif + + + + float3 lightDir; + float3 diffuse = float3(0,0,0); + float d; + + @shForeach(@shGlobalSettingString(terrain_num_lights)) + + lightDir = lightPosObjSpace@shIterator.xyz - (objSpacePosition.xyz * lightPosObjSpace@shIterator.w); + d = length(lightDir); + + + lightDir = normalize(lightDir); + +#if @shIterator == 0 + + #if (SHADOWS || SHADOWS_PSSM) + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * shadow * caustics; + + #else + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0) * caustics; + + #endif + +#else + diffuse += lightDiffuse@shIterator.xyz * (1.0 / ((lightAttenuation@shIterator.y) + (lightAttenuation@shIterator.z * d) + (lightAttenuation@shIterator.w * d * d))) * max(dot(normal, lightDir), 0); +#endif + + @shEndForeach + + shOutputColour(0).xyz *= (lightAmbient.xyz + diffuse); +#endif + + + + +#if FOG + float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); + + #if UNDERWATER + // regular fog only if fragment is above water + if (worldPos.y > waterLevel) + #endif + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); +#endif + + // prevent negative colour output (for example with negative lights) + shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); + +#if UNDERWATER + float fogAmount = (cameraPos.y > waterLevel) + ? shSaturate(length(waterEyePos-worldPos) / VISIBILITY) + : shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY); + + float3 eyeVec = normalize(cameraPos.xyz-worldPos); + + float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); + waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); + float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; + + float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); + waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); + float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; + float3 waterext = float3(0.6, 0.9, 1.0);//water extinction + watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); + watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; + + + float darkness = VISIBILITY*2.0; + darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0); + watercolour *= darkness; + + float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0; + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); +#endif + + +#if MRT + shOutputColour(1) = float4(depth / far,1,1,1); +#endif + } + +#endif diff --git a/files/materials/terrain.shaderset b/files/materials/terrain.shaderset new file mode 100644 index 000000000..a72f2358f --- /dev/null +++ b/files/materials/terrain.shaderset @@ -0,0 +1,15 @@ +shader_set terrain_vertex +{ + source terrain.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_3_0 vs_2_0 +} + +shader_set terrain_fragment +{ + source terrain.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} diff --git a/files/materials/underwater.h b/files/materials/underwater.h new file mode 100644 index 000000000..18052a98d --- /dev/null +++ b/files/materials/underwater.h @@ -0,0 +1,118 @@ +#define VISIBILITY 1500.0 // how far you can look through water + +#define BIG_WAVES_X 0.3 // strength of big waves +#define BIG_WAVES_Y 0.3 + +#define MID_WAVES_X 0.3 // strength of middle sized waves +#define MID_WAVES_Y 0.15 + +#define SMALL_WAVES_X 0.15 // strength of small waves +#define SMALL_WAVES_Y 0.1 + +#define WAVE_CHOPPYNESS 0.15 // wave choppyness +#define WAVE_SCALE 0.01 // overall wave scale + +#define ABBERATION 0.001 // chromatic abberation amount + +#define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction + +float3 intercept(float3 lineP, + float3 lineN, + float3 planeN, + float planeD) +{ + + float distance = (planeD - dot(planeN, lineP)) / dot(lineN, planeN); + return lineP + lineN * distance; +} + +float3 perturb1(shTexture2D tex, float2 coords, float bend, float2 windDir, float windSpeed, float timer) +{ + float2 nCoord = float2(0,0); + bend *= WAVE_CHOPPYNESS; + nCoord = coords * (WAVE_SCALE * 0.05) + windDir * timer * (windSpeed*0.04); + float3 normal0 = 2.0 * shSample(tex, nCoord + float2(-timer*0.015,-timer*0.05)).rgb - 1.0; + nCoord = coords * (WAVE_SCALE * 0.1) + windDir * timer * (windSpeed*0.08)-normal0.xy*bend; + float3 normal1 = 2.0 * shSample(tex, nCoord + float2(+timer*0.020,+timer*0.015)).rgb - 1.0; + + nCoord = coords * (WAVE_SCALE * 0.25) + windDir * timer * (windSpeed*0.07)-normal1.xy*bend; + float3 normal2 = 2.0 * shSample(tex, nCoord + float2(-timer*0.04,-timer*0.03)).rgb - 1.0; + nCoord = coords * (WAVE_SCALE * 0.5) + windDir * timer * (windSpeed*0.09)-normal2.xy*bend; + float3 normal3 = 2.0 * shSample(tex, nCoord + float2(+timer*0.03,+timer*0.04)).rgb - 1.0; + + nCoord = coords * (WAVE_SCALE* 1.0) + windDir * timer * (windSpeed*0.4)-normal3.xy*bend; + float3 normal4 = 2.0 * shSample(tex, nCoord + float2(-timer*0.2,+timer*0.1)).rgb - 1.0; + nCoord = coords * (WAVE_SCALE * 2.0) + windDir * timer * (windSpeed*0.7)-normal4.xy*bend; + float3 normal5 = 2.0 * shSample(tex, nCoord + float2(+timer*0.1,-timer*0.06)).rgb - 1.0; + + + float3 normal = normalize(normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); + return normal; +} + +float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float windSpeed, float timer) +{ + bend *= WAVE_CHOPPYNESS; + float3 col = float3(0,0,0); + float2 nCoord = float2(0,0); //normal coords + + nCoord = coords * (WAVE_SCALE * 0.025) + windDir * timer * (windSpeed*0.03); + col += shSample(tex,nCoord + float2(-timer*0.005,-timer*0.01)).rgb*0.20; + nCoord = coords * (WAVE_SCALE * 0.1) + windDir * timer * (windSpeed*0.05)-(col.xy/col.zz)*bend; + col += shSample(tex,nCoord + float2(+timer*0.01,+timer*0.005)).rgb*0.20; + + nCoord = coords * (WAVE_SCALE * 0.2) + windDir * timer * (windSpeed*0.1)-(col.xy/col.zz)*bend; + col += shSample(tex,nCoord + float2(-timer*0.02,-timer*0.03)).rgb*0.20; + nCoord = coords * (WAVE_SCALE * 0.5) + windDir * timer * (windSpeed*0.2)-(col.xy/col.zz)*bend; + col += shSample(tex,nCoord + float2(+timer*0.03,+timer*0.02)).rgb*0.15; + + nCoord = coords * (WAVE_SCALE* 0.8) + windDir * timer * (windSpeed*1.0)-(col.xy/col.zz)*bend; + col += shSample(tex, nCoord + float2(-timer*0.06,+timer*0.08)).rgb*0.15; + nCoord = coords * (WAVE_SCALE * 1.0) + windDir * timer * (windSpeed*1.3)-(col.xy/col.zz)*bend; + col += shSample(tex,nCoord + float2(+timer*0.08,-timer*0.06)).rgb*0.10; + + return col; +} + + +float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 waterEyePos, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed) +{ + float waterDepth = shSaturate((waterEyePos.y - worldPos.y) / 50.0); + + float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,1,0), waterLevel); + + ///\ todo clean this up + float causticdepth = length(causticPos-worldPos.xyz); + causticdepth = 1.0-shSaturate(causticdepth / VISIBILITY); + causticdepth = shSaturate(causticdepth); + + // NOTE: the original shader calculated a tangent space basis here, + // but using only the world normal is cheaper and i couldn't see a visual difference + // also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information + float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xzy * 2 - 1; + + //float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0); + + float NdotL = max(dot(worldNormal.xyz, lightDirectionWS0.xyz),0.0); + + float causticR = 1.0-perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + + /// \todo sunFade + + // float3 caustics = clamp(pow(float3(causticR)*5.5,float3(5.5*causticdepth)),0.0,1.0)*NdotL*sunFade*causticdepth; + float3 caustics = clamp(pow(float3(causticR,causticR,causticR)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)),0.0,1.0)*NdotL*causticdepth; + float causticG = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + float causticB = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z; + //caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth; + caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth,5.5*causticdepth,5.5*causticdepth)))*NdotL*causticdepth; + + caustics *= 3; + + // shore transition + caustics = shLerp (float3(1,1,1), caustics, waterDepth); + + return caustics; +} + diff --git a/files/materials/water.mat b/files/materials/water.mat new file mode 100644 index 000000000..dcea5a0d0 --- /dev/null +++ b/files/materials/water.mat @@ -0,0 +1,55 @@ +material Water +{ + pass + { + emissive 0.6 0.7 1.0 + ambient 0 0 0 + diffuse 0 0 0 1 + specular 0 0 0 32 + + vertex_program water_vertex + fragment_program water_fragment + + cull_hardware none + + texture_unit reflectionMap + { + texture_alias WaterReflection + tex_address_mode clamp + } + + texture_unit refractionMap + { + texture_alias WaterRefraction + tex_address_mode clamp + } + + texture_unit depthMap + { + texture_alias SceneDepth + tex_address_mode clamp + } + + texture_unit normalMap + { + direct_texture water_nm.png + } + + + // for simple_water + texture_unit animatedTexture + { + create_in_ffp true + scale 0.1 0.1 + alpha_op_ex source1 src_manual src_current 0.7 + } + } +} + + +material Underwater_Dome +{ + parent openmw_objects_base + + depth_write off +} diff --git a/files/materials/water.shader b/files/materials/water.shader new file mode 100644 index 000000000..8f46aed34 --- /dev/null +++ b/files/materials/water.shader @@ -0,0 +1,311 @@ +#include "core.h" + + +#define SIMPLE_WATER @shGlobalSettingBool(simple_water) + + +#if SIMPLE_WATER + // --------------------------------------- SIMPLE WATER --------------------------------------------------- + + + #define MRT @shGlobalSettingBool(mrt_output) + + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shVertexInput(float2, uv0) + shOutput(float2, UV) + shOutput(float, depth) + + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + depth = shOutputPosition.z; + } + +#else + + SH_BEGIN_PROGRAM + shSampler2D(animatedTexture) + shInput(float2, UV) + shInput(float, depth) +#if MRT + shDeclareMrtOutput(1) +#endif + + shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) + shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) + + + SH_START_PROGRAM + { + shOutputColour(0).xyz = shSample(animatedTexture, UV * 15).xyz * float3(0.6, 0.7, 1.0); + shOutputColour(0).w = 0.7; + + float fogValue = shSaturate((depth - fogParams.y) * fogParams.w); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); + +#if MRT + shOutputColour(1) = float4(1,1,1,1); +#endif + } + +#endif + +#else + + + +// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) + + + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM + shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shVertexInput(float2, uv0) + shOutput(float2, UV) + + shOutput(float3, screenCoordsPassthrough) + shOutput(float4, position) + shOutput(float, depthPassthrough) + + SH_START_PROGRAM + { + shOutputPosition = shMatrixMult(wvp, shInputPosition); + UV = uv0; + + + #if !SH_GLSL + float4x4 scalemat = float4x4( 0.5, 0, 0, 0.5, + 0, -0.5, 0, 0.5, + 0, 0, 0.5, 0.5, + 0, 0, 0, 1 ); + #else + mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0, + 0.0, -0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0); + #endif + + float4 texcoordProj = shMatrixMult(scalemat, shOutputPosition); + screenCoordsPassthrough = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w); + + position = shInputPosition; + + depthPassthrough = shOutputPosition.z; + } + +#else + + // tweakables ---------------------------------------------------- + + #define VISIBILITY 1500.0 // how far you can look through water + + #define BIG_WAVES_X 0.3 // strength of big waves + #define BIG_WAVES_Y 0.3 + + #define MID_WAVES_X 0.3 // strength of middle sized waves + #define MID_WAVES_Y 0.15 + + #define SMALL_WAVES_X 0.15 // strength of small waves + #define SMALL_WAVES_Y 0.1 + + #define WAVE_CHOPPYNESS 0.15 // wave choppyness + #define WAVE_SCALE 75 // overall wave scale + + #define BUMP 1.5 // overall water surface bumpiness + #define REFL_BUMP 0.08 // reflection distortion amount + #define REFR_BUMP 0.06 // refraction distortion amount + + #define SCATTER_AMOUNT 3.0 // amount of sunlight scattering + #define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering + + #define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction + + #define SPEC_HARDNESS 256 // specular highlights hardness + + + // --------------------------------------------------------------- + + + + float fresnel_dielectric(float3 Incoming, float3 Normal, float eta) + { + /* compute fresnel reflectance without explicitly computing + the refracted direction */ + float c = abs(dot(Incoming, Normal)); + float g = eta * eta - 1.0 + c * c; + float result; + + if(g > 0.0) { + g = sqrt(g); + float A =(g - c)/(g + c); + float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0); + result = 0.5 * A * A *(1.0 + B * B); + } + else + result = 1.0; /* TIR (no refracted component) */ + + return result; + } + + SH_BEGIN_PROGRAM + shInput(float2, UV) + shInput(float3, screenCoordsPassthrough) + shInput(float4, position) + shInput(float, depthPassthrough) + + shUniform(float, far) @shAutoConstant(far, far_clip_distance) + + shSampler2D(reflectionMap) + shSampler2D(refractionMap) + shSampler2D(depthMap) + shSampler2D(normalMap) + + shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) + #define WIND_SPEED windDir_windSpeed.z + #define WIND_DIR windDir_windSpeed.xy + + shUniform(float, waterTimer) @shSharedParameter(waterTimer) + shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight) + + shUniform(float4, sunPosition) @shAutoConstant(sunPosition, light_position, 0) + shUniform(float4, sunSpecular) @shAutoConstant(sunSpecular, light_specular_colour, 0) + + + + shUniform(float, renderTargetFlipping) @shAutoConstant(renderTargetFlipping, render_target_flipping) + + + shUniform(float3, fogColor) @shAutoConstant(fogColor, fog_colour) + shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) + + shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position_object_space) + + + SH_START_PROGRAM + { + + float2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; + screenCoords.y = (1-shSaturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; + + float depth = shSample(depthMap, screenCoords).x * far - depthPassthrough; + float shoreFade = shSaturate(depth / 50.0); + + float2 nCoord = float2(0,0); + + nCoord = UV * (WAVE_SCALE * 0.05) + WIND_DIR * waterTimer * (WIND_SPEED*0.04); + float3 normal0 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.015,-waterTimer*0.005)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 0.1) + WIND_DIR * waterTimer * (WIND_SPEED*0.08)-(normal0.xy/normal0.zz)*WAVE_CHOPPYNESS; + float3 normal1 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.020,+waterTimer*0.015)).rgb - 1.0; + + nCoord = UV * (WAVE_SCALE * 0.25) + WIND_DIR * waterTimer * (WIND_SPEED*0.07)-(normal1.xy/normal1.zz)*WAVE_CHOPPYNESS; + float3 normal2 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.04,-waterTimer*0.03)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 0.5) + WIND_DIR * waterTimer * (WIND_SPEED*0.09)-(normal2.xy/normal2.z)*WAVE_CHOPPYNESS; + float3 normal3 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.03,+waterTimer*0.04)).rgb - 1.0; + + nCoord = UV * (WAVE_SCALE* 1.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.4)-(normal3.xy/normal3.zz)*WAVE_CHOPPYNESS; + float3 normal4 = 2.0 * shSample(normalMap, nCoord + float2(-waterTimer*0.02,+waterTimer*0.1)).rgb - 1.0; + nCoord = UV * (WAVE_SCALE * 2.0) + WIND_DIR * waterTimer * (WIND_SPEED*0.7)-(normal4.xy/normal4.zz)*WAVE_CHOPPYNESS; + float3 normal5 = 2.0 * shSample(normalMap, nCoord + float2(+waterTimer*0.1,-waterTimer*0.06)).rgb - 1.0; + + + + float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y + + normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xzy; + + normal = normalize(float3(normal.x * BUMP, normal.y, normal.z * BUMP)); + + // normal for sunlight scattering + float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 + + normal2 * MID_WAVES_X*0.2 + normal3 * MID_WAVES_Y*0.2 + + normal4 * SMALL_WAVES_X*0.1 + normal5 * SMALL_WAVES_Y*0.1).xzy; + lNormal = normalize(float3(lNormal.x * BUMP, lNormal.y, lNormal.z * BUMP)); + + + float3 lVec = normalize(sunPosition.xyz); + float3 vVec = normalize(position.xyz - cameraPos.xyz); + + + float isUnderwater = (cameraPos.y > 0) ? 0.0 : 1.0; + + // sunlight scattering + float3 pNormal = float3(0,1,0); + float3 lR = reflect(lVec, lNormal); + float3 llR = reflect(lVec, pNormal); + + float s = shSaturate(dot(lR, vVec)*2.0-1.2); + float lightScatter = shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); + float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*float3(1.0,0.4,0.0), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); + + // fresnel + float ior = (cameraPos.y>0)?(1.333/1.0):(1.0/1.333); //air to water; water to air + float fresnel = fresnel_dielectric(-vVec, normal, ior); + + fresnel = shSaturate(fresnel); + + // reflection + float3 reflection = shSample(reflectionMap, screenCoords+(normal.xz*REFL_BUMP)).rgb; + + // refraction + float3 R = reflect(vVec, normal); + + // check the depth at the refracted coords, and don't do any normal distortion for the refraction if the object to refract + // is actually above the water (objectDepth < waterDepth) + // this solves silhouettes around objects above the water + float refractDepth = shSample(depthMap, screenCoords-(shoreFade * normal.xz*REFR_BUMP)).x * far - depthPassthrough; + float doRefraction = (refractDepth < 0) ? 0.f : 1.f; + + float3 refraction = float3(0,0,0); + refraction.rgb = shSample(refractionMap, (screenCoords-(shoreFade * normal.xz*REFR_BUMP * doRefraction))*1.0).rgb; + + // brighten up the refraction underwater + refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction; + + // specular + float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); + + shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; + + // smooth transition to shore (above water only) + shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, refraction, (1-shoreFade) * (1-isUnderwater)); + + // fog + if (isUnderwater == 1) + { + float waterSunGradient = dot(-vVec, -lVec); + waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); + float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; + + float waterGradient = dot(-vVec, float3(0.0,-1.0,0.0)); + waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); + float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; + float3 waterext = float3(0.6, 0.9, 1.0);//water extinction + watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); + + float darkness = VISIBILITY*2.0; + darkness = clamp((cameraPos.y+darkness)/darkness,0.2,1.0); + + + float fog = shSaturate(length(cameraPos.xyz-position.xyz) / VISIBILITY); + shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, watercolour * darkness, shSaturate(fog / waterext)); + } + else + { + float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue); + } + + shOutputColour(0).w = 1; + } + +#endif + + +#endif diff --git a/files/materials/water.shaderset b/files/materials/water.shaderset new file mode 100644 index 000000000..5e070a45a --- /dev/null +++ b/files/materials/water.shaderset @@ -0,0 +1,15 @@ +shader_set water_vertex +{ + source water.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_3_0 vs_2_0 +} + +shader_set water_fragment +{ + source water.shader + type fragment + profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index dad4afb46..3a5430c6f 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -1,68 +1,73 @@ -# Minimal MyGUI build system for OpenMW # Copy resource files into the build directory set(SDIR ${CMAKE_CURRENT_SOURCE_DIR}) set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) -configure_file("${SDIR}/bigbars.png" "${DDIR}/bigbars.png" COPYONLY) -configure_file("${SDIR}/black.png" "${DDIR}/black.png" COPYONLY) -configure_file("${SDIR}/core.skin" "${DDIR}/core.skin" COPYONLY) -configure_file("${SDIR}/core.xml" "${DDIR}/core.xml" COPYONLY) -configure_file("${SDIR}/mwgui.png" "${DDIR}/mwgui.png" COPYONLY) -configure_file("${SDIR}/openmw_resources.xml" "${DDIR}/openmw_resources.xml" COPYONLY) -configure_file("${SDIR}/openmw_settings.xml" "${DDIR}/openmw_settings.xml" COPYONLY) -configure_file("${SDIR}/openmw_box.skin.xml" "${DDIR}/openmw_box.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_button.skin.xml" "${DDIR}/openmw_button.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_list.skin.xml" "${DDIR}/openmw_list.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_edit.skin.xml" "${DDIR}/openmw_edit.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_console_layout.xml" "${DDIR}/openmw_console_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_console.skin.xml" "${DDIR}/openmw_console.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw.font.xml" "${DDIR}/openmw.font.xml" COPYONLY) -configure_file("${SDIR}/openmw_hud_box.skin.xml" "${DDIR}/openmw_hud_box.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_hud_energybar.skin.xml" "${DDIR}/openmw_hud_energybar.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_hud_layout.xml" "${DDIR}/openmw_hud_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_text_input_layout.xml" "${DDIR}/openmw_text_input_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_infobox_layout.xml" "${DDIR}/openmw_infobox_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_race_layout.xml" "${DDIR}/openmw_chargen_race_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_class_layout.xml" "${DDIR}/openmw_chargen_class_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_generate_class_result_layout.xml" "${DDIR}/openmw_chargen_generate_class_result_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_create_class_layout.xml" "${DDIR}/openmw_chargen_create_class_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_select_specialization_layout.xml" "${DDIR}/openmw_chargen_select_specialization_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_select_attribute_layout.xml" "${DDIR}/openmw_chargen_select_attribute_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_select_skill_layout.xml" "${DDIR}/openmw_chargen_select_skill_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_class_description_layout.xml" "${DDIR}/openmw_chargen_class_description_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_birth_layout.xml" "${DDIR}/openmw_chargen_birth_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_chargen_review_layout.xml" "${DDIR}/openmw_chargen_review_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_dialogue_window_layout.xml" "${DDIR}/openmw_dialogue_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_dialogue_window_skin.xml" "${DDIR}/openmw_dialogue_window_skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_inventory_window_layout.xml" "${DDIR}/openmw_inventory_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_container_window_layout.xml" "${DDIR}/openmw_container_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_layers.xml" "${DDIR}/openmw_layers.xml" COPYONLY) -configure_file("${SDIR}/openmw_mainmenu_layout.xml" "${DDIR}/openmw_mainmenu_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_mainmenu_skin.xml" "${DDIR}/openmw_mainmenu_skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_map_window_layout.xml" "${DDIR}/openmw_map_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_map_window_skin.xml" "${DDIR}/openmw_map_window_skin.xml" COPYONLY) -configure_file("${SDIR}/openmw.pointer.xml" "${DDIR}/openmw.pointer.xml" COPYONLY) -configure_file("${SDIR}/openmw_progress.skin.xml" "${DDIR}/openmw_progress.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_stats_window_layout.xml" "${DDIR}/openmw_stats_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_text.skin.xml" "${DDIR}/openmw_text.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_windows.skin.xml" "${DDIR}/openmw_windows.skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_messagebox_layout.xml" "${DDIR}/openmw_messagebox_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_interactive_messagebox_layout.xml" "${DDIR}/openmw_interactive_messagebox_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_journal_layout.xml" "${DDIR}/openmw_journal_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_journal_skin.xml" "${DDIR}/openmw_journal_skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_tooltips.xml" "${DDIR}/openmw_tooltips.xml" COPYONLY) -configure_file("${SDIR}/openmw_scroll_layout.xml" "${DDIR}/openmw_scroll_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_scroll_skin.xml" "${DDIR}/openmw_scroll_skin.xml" COPYONLY) -configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_count_window_layout.xml" "${DDIR}/openmw_count_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_trade_window_layout.xml" "${DDIR}/openmw_trade_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_settings_window_layout.xml" "${DDIR}/openmw_settings_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_confirmation_dialog_layout.xml" "${DDIR}/openmw_confirmation_dialog_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_alchemy_window_layout.xml" "${DDIR}/openmw_alchemy_window_layout.xml" COPYONLY) -configure_file("${SDIR}/openmw_spell_window_layout.xml" "${DDIR}/openmw_spell_window_layout.xml" COPYONLY) -configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) -configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) -configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) -configure_file("${SDIR}/Obliviontt.zip" "${DDIR}/Obliviontt.zip" COPYONLY) -configure_file("${SDIR}/VeraMono.ttf" "${DDIR}/VeraMono.ttf" COPYONLY) +set(MYGUI_FILES + atlas1.cfg + mainmenu.cfg + bigbars.png + black.png + core.skin + core.xml + EBGaramond-Regular.ttf + mwgui.png + Obliviontt.zip + openmw_alchemy_window.layout + openmw_book.layout + openmw_box.skin.xml + openmw_button.skin.xml + openmw_chargen_birth.layout + openmw_chargen_class_description.layout + openmw_chargen_class.layout + openmw_chargen_create_class.layout + openmw_chargen_generate_class_result.layout + openmw_chargen_race.layout + openmw_chargen_review.layout + openmw_chargen_select_attribute.layout + openmw_chargen_select_skill.layout + openmw_chargen_select_specialization.layout + openmw_confirmation_dialog.layout + openmw_console.layout + openmw_console.skin.xml + openmw_container_window.layout + openmw_count_window.layout + openmw_dialogue_window.layout + openmw_dialogue_window_skin.xml + openmw_edit.skin.xml + openmw.font.xml + openmw_hud_box.skin.xml + openmw_hud_energybar.skin.xml + openmw_hud.layout + openmw_infobox.layout + openmw_interactive_messagebox.layout + openmw_inventory_window.layout + openmw_journal.layout + openmw_journal_skin.xml + openmw_layers.xml + openmw_list.skin.xml + openmw_mainmenu.layout + openmw_mainmenu_skin.xml + openmw_map_window.layout + openmw_map_window_skin.xml + openmw_messagebox.layout + openmw.pointer.xml + openmw_progress.skin.xml + openmw_resources.xml + openmw_scroll.layout + openmw_scroll_skin.xml + openmw_settings_window.layout + openmw_settings.xml + openmw_spell_window.layout + openmw_stats_window.layout + openmw_text_input.layout + openmw_text.skin.xml + openmw_tooltips.layout + openmw_trade_window.layout + openmw_windows.skin.xml + smallbars.png + VeraMono.ttf +) + + +copy_all_files(${CMAKE_CURRENT_SOURCE_DIR} ${DDIR} "${MYGUI_FILES}") diff --git a/files/mygui/EBGaramond-Regular.ttf b/files/mygui/EBGaramond-Regular.ttf index dde486903..3f6f6c191 100644 Binary files a/files/mygui/EBGaramond-Regular.ttf and b/files/mygui/EBGaramond-Regular.ttf differ diff --git a/files/mygui/mainmenu.cfg b/files/mygui/mainmenu.cfg new file mode 100644 index 000000000..7aaf8c1c7 --- /dev/null +++ b/files/mygui/mainmenu.cfg @@ -0,0 +1,95 @@ +[settings] + size_x = 512 + size_y = 512 + + +[menu_newgame.dds] + x = 0 + y = 0 + +[menu_newgame_pressed.dds] + x = 128 + y = 0 + +[menu_newgame_over.dds] + x = 256 + y = 0 + + +[menu_loadgame.dds] + x = 384 + y = 0 + +[menu_loadgame_pressed.dds] + x = 0 + y = 64 + +[menu_loadgame_over.dds] + x = 128 + y = 64 + + +[menu_options.dds] + x = 256 + y = 64 + +[menu_options_pressed.dds] + x = 384 + y = 64 + +[menu_options_over.dds] + x = 0 + y = 128 + + +[menu_credits.dds] + x = 128 + y = 128 + +[menu_credits_pressed.dds] + x = 256 + y = 128 + +[menu_credits_over.dds] + x = 384 + y = 128 + + +[menu_exitgame.dds] + x = 0 + y = 192 + +[menu_exitgame_pressed.dds] + x = 128 + y = 192 + +[menu_exitgame_over.dds] + x = 256 + y = 192 + + +[menu_savegame.dds] + x = 384 + y = 192 + +[menu_savegame_pressed.dds] + x = 0 + y = 256 + +[menu_savegame_over.dds] + x = 128 + y = 256 + + +[menu_return.dds] + x = 256 + y = 256 + +[menu_return_pressed.dds] + x = 384 + y = 256 + +[menu_return_over.dds] + x = 0 + y = 320 + diff --git a/files/mygui/openmw_alchemy_window_layout.xml b/files/mygui/openmw_alchemy_window.layout similarity index 100% rename from files/mygui/openmw_alchemy_window_layout.xml rename to files/mygui/openmw_alchemy_window.layout diff --git a/files/mygui/openmw_book_layout.xml b/files/mygui/openmw_book.layout similarity index 100% rename from files/mygui/openmw_book_layout.xml rename to files/mygui/openmw_book.layout diff --git a/files/mygui/openmw_chargen_birth_layout.xml b/files/mygui/openmw_chargen_birth.layout similarity index 100% rename from files/mygui/openmw_chargen_birth_layout.xml rename to files/mygui/openmw_chargen_birth.layout diff --git a/files/mygui/openmw_chargen_class_layout.xml b/files/mygui/openmw_chargen_class.layout similarity index 100% rename from files/mygui/openmw_chargen_class_layout.xml rename to files/mygui/openmw_chargen_class.layout diff --git a/files/mygui/openmw_chargen_class_description_layout.xml b/files/mygui/openmw_chargen_class_description.layout similarity index 100% rename from files/mygui/openmw_chargen_class_description_layout.xml rename to files/mygui/openmw_chargen_class_description.layout diff --git a/files/mygui/openmw_chargen_create_class_layout.xml b/files/mygui/openmw_chargen_create_class.layout similarity index 100% rename from files/mygui/openmw_chargen_create_class_layout.xml rename to files/mygui/openmw_chargen_create_class.layout diff --git a/files/mygui/openmw_chargen_generate_class_result_layout.xml b/files/mygui/openmw_chargen_generate_class_result.layout similarity index 100% rename from files/mygui/openmw_chargen_generate_class_result_layout.xml rename to files/mygui/openmw_chargen_generate_class_result.layout diff --git a/files/mygui/openmw_chargen_race_layout.xml b/files/mygui/openmw_chargen_race.layout similarity index 100% rename from files/mygui/openmw_chargen_race_layout.xml rename to files/mygui/openmw_chargen_race.layout diff --git a/files/mygui/openmw_chargen_review_layout.xml b/files/mygui/openmw_chargen_review.layout similarity index 100% rename from files/mygui/openmw_chargen_review_layout.xml rename to files/mygui/openmw_chargen_review.layout diff --git a/files/mygui/openmw_chargen_select_attribute_layout.xml b/files/mygui/openmw_chargen_select_attribute.layout similarity index 100% rename from files/mygui/openmw_chargen_select_attribute_layout.xml rename to files/mygui/openmw_chargen_select_attribute.layout diff --git a/files/mygui/openmw_chargen_select_skill_layout.xml b/files/mygui/openmw_chargen_select_skill.layout similarity index 100% rename from files/mygui/openmw_chargen_select_skill_layout.xml rename to files/mygui/openmw_chargen_select_skill.layout diff --git a/files/mygui/openmw_chargen_select_specialization_layout.xml b/files/mygui/openmw_chargen_select_specialization.layout similarity index 100% rename from files/mygui/openmw_chargen_select_specialization_layout.xml rename to files/mygui/openmw_chargen_select_specialization.layout diff --git a/files/mygui/openmw_confirmation_dialog_layout.xml b/files/mygui/openmw_confirmation_dialog.layout similarity index 100% rename from files/mygui/openmw_confirmation_dialog_layout.xml rename to files/mygui/openmw_confirmation_dialog.layout diff --git a/files/mygui/openmw_console_layout.xml b/files/mygui/openmw_console.layout similarity index 100% rename from files/mygui/openmw_console_layout.xml rename to files/mygui/openmw_console.layout diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window.layout similarity index 100% rename from files/mygui/openmw_container_window_layout.xml rename to files/mygui/openmw_container_window.layout diff --git a/files/mygui/openmw_count_window_layout.xml b/files/mygui/openmw_count_window.layout similarity index 100% rename from files/mygui/openmw_count_window_layout.xml rename to files/mygui/openmw_count_window.layout diff --git a/files/mygui/openmw_dialogue_window_layout.xml b/files/mygui/openmw_dialogue_window.layout similarity index 100% rename from files/mygui/openmw_dialogue_window_layout.xml rename to files/mygui/openmw_dialogue_window.layout diff --git a/files/mygui/openmw_hud_layout.xml b/files/mygui/openmw_hud.layout similarity index 100% rename from files/mygui/openmw_hud_layout.xml rename to files/mygui/openmw_hud.layout diff --git a/files/mygui/openmw_infobox_layout.xml b/files/mygui/openmw_infobox.layout similarity index 100% rename from files/mygui/openmw_infobox_layout.xml rename to files/mygui/openmw_infobox.layout diff --git a/files/mygui/openmw_interactive_messagebox_layout.xml b/files/mygui/openmw_interactive_messagebox.layout similarity index 100% rename from files/mygui/openmw_interactive_messagebox_layout.xml rename to files/mygui/openmw_interactive_messagebox.layout diff --git a/files/mygui/openmw_inventory_window_layout.xml b/files/mygui/openmw_inventory_window.layout similarity index 100% rename from files/mygui/openmw_inventory_window_layout.xml rename to files/mygui/openmw_inventory_window.layout diff --git a/files/mygui/openmw_journal_layout.xml b/files/mygui/openmw_journal.layout similarity index 100% rename from files/mygui/openmw_journal_layout.xml rename to files/mygui/openmw_journal.layout diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index 56f800ea3..7a8d586d2 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -4,8 +4,6 @@ - - diff --git a/files/mygui/openmw_mainmenu.layout b/files/mygui/openmw_mainmenu.layout new file mode 100644 index 000000000..4479a121f --- /dev/null +++ b/files/mygui/openmw_mainmenu.layout @@ -0,0 +1,6 @@ + + + + + + diff --git a/files/mygui/openmw_mainmenu_layout.xml b/files/mygui/openmw_mainmenu_layout.xml deleted file mode 100644 index bf17be7f7..000000000 --- a/files/mygui/openmw_mainmenu_layout.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/files/mygui/openmw_map_window_layout.xml b/files/mygui/openmw_map_window.layout similarity index 100% rename from files/mygui/openmw_map_window_layout.xml rename to files/mygui/openmw_map_window.layout diff --git a/files/mygui/openmw_messagebox_layout.xml b/files/mygui/openmw_messagebox.layout similarity index 100% rename from files/mygui/openmw_messagebox_layout.xml rename to files/mygui/openmw_messagebox.layout diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index f1a8b0dfc..83461bbe8 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -1,6 +1,8 @@ + + @@ -44,6 +46,10 @@ + + + + @@ -113,6 +119,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_scroll_layout.xml b/files/mygui/openmw_scroll.layout similarity index 100% rename from files/mygui/openmw_scroll_layout.xml rename to files/mygui/openmw_scroll.layout diff --git a/files/mygui/openmw_settings_window_layout.xml b/files/mygui/openmw_settings_window.layout similarity index 75% rename from files/mygui/openmw_settings_window_layout.xml rename to files/mygui/openmw_settings_window.layout index 7c508b1e9..a14606ade 100644 --- a/files/mygui/openmw_settings_window_layout.xml +++ b/files/mygui/openmw_settings_window.layout @@ -1,7 +1,10 @@ - + + + + @@ -100,6 +103,12 @@ + + + + + + @@ -179,6 +188,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_spell_window_layout.xml b/files/mygui/openmw_spell_window.layout similarity index 100% rename from files/mygui/openmw_spell_window_layout.xml rename to files/mygui/openmw_spell_window.layout diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window.layout similarity index 100% rename from files/mygui/openmw_stats_window_layout.xml rename to files/mygui/openmw_stats_window.layout diff --git a/files/mygui/openmw_text_input_layout.xml b/files/mygui/openmw_text_input.layout similarity index 100% rename from files/mygui/openmw_text_input_layout.xml rename to files/mygui/openmw_text_input.layout diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.layout similarity index 100% rename from files/mygui/openmw_tooltips.xml rename to files/mygui/openmw_tooltips.layout diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window.layout similarity index 100% rename from files/mygui/openmw_trade_window_layout.xml rename to files/mygui/openmw_trade_window.layout diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index b379f84ce..a9eb23d68 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -322,6 +322,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/plugins.cfg.linux b/files/plugins.cfg.linux deleted file mode 100644 index f34621a0f..000000000 --- a/files/plugins.cfg.linux +++ /dev/null @@ -1,12 +0,0 @@ -# Defines plugins to load - -# Define plugin folder -PluginFolder=${OGRE_PLUGIN_DIR_REL} - -# Define plugins -Plugin=RenderSystem_GL -Plugin=Plugin_ParticleFX -Plugin=Plugin_OctreeSceneManager -Plugin=Plugin_CgProgramManager - - diff --git a/files/plugins.cfg.mac b/files/plugins.cfg.mac deleted file mode 100644 index 322070832..000000000 --- a/files/plugins.cfg.mac +++ /dev/null @@ -1,12 +0,0 @@ -# Defines plugins to load - -# Define plugin folder -PluginFolder=${OGRE_PLUGIN_DIR} - -# Define plugins -Plugin=RenderSystem_GL.1.8.0 -Plugin=Plugin_ParticleFX.1.8.0 -Plugin=Plugin_OctreeSceneManager.1.8.0 -Plugin=Plugin_CgProgramManager.1.8.0 - - diff --git a/files/plugins.cfg.win32 b/files/plugins.cfg.win32 deleted file mode 100644 index ea12c0394..000000000 --- a/files/plugins.cfg.win32 +++ /dev/null @@ -1,13 +0,0 @@ -# Defines plugins to load - -# Define plugin folder -PluginFolder=.\ - -# Define plugins -Plugin=RenderSystem_Direct3D9 -Plugin=RenderSystem_GL -Plugin=Plugin_ParticleFX -Plugin=Plugin_OctreeSceneManager -Plugin=Plugin_CgProgramManager - - diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 883f32ae0..a723e307c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -48,6 +48,8 @@ anisotropy = 4 # Number of texture mipmaps to generate num mipmaps = 5 +shader mode = + [Shadows] # Shadows are only supported when object shaders are on! enabled = false @@ -74,6 +76,8 @@ statics shadows = true # Fraction of the total shadow distance after which the shadow starts to fade out fade start = 0.8 +debug = false + [HUD] # FPS counter # 0: not visible diff --git a/files/shadows/depthshadowcaster.cg b/files/shadows/depthshadowcaster.cg deleted file mode 100644 index 3457a4f8d..000000000 --- a/files/shadows/depthshadowcaster.cg +++ /dev/null @@ -1,51 +0,0 @@ -void main_vp( - float4 position : POSITION, - float2 uv : TEXCOORD0, - - out float4 oPosition : POSITION, - out float2 oDepth : TEXCOORD0, - out float2 oUv : TEXCOORD1, - - uniform float4x4 wvpMat) -{ - // this is the view space position - oPosition = mul(wvpMat, position); - - // depth info for the fragment. - oDepth.x = oPosition.z; - oDepth.y = oPosition.w; - - // clamp z to zero. seem to do the trick. :-/ - oPosition.z = max(oPosition.z, 0); - - oUv = uv; -} - -void main_fp( - float2 depth : TEXCOORD0, - float2 uv : TEXCOORD1, - uniform sampler2D texture1 : register(s0), - - out float4 oColour : COLOR) -{ - float finalDepth = depth.x / depth.y; - - // use alpha channel of the first texture - float alpha = tex2D(texture1, uv).a; - - // discard if alpha is less than 0.5 - clip((alpha >= 0.5) ? 1 : -1); - - oColour = float4(finalDepth, finalDepth, finalDepth, 1); -} - -void main_fp_noalpha( - float2 depth : TEXCOORD0, - float2 uv : TEXCOORD1, - - out float4 oColour : COLOR) -{ - float finalDepth = depth.x / depth.y; - - oColour = float4(finalDepth, finalDepth, finalDepth, 1); -} diff --git a/files/shadows/depthshadowcaster.material b/files/shadows/depthshadowcaster.material deleted file mode 100644 index f645cad01..000000000 --- a/files/shadows/depthshadowcaster.material +++ /dev/null @@ -1,73 +0,0 @@ -vertex_program depth_shadow_caster_vs cg -{ - source depthshadowcaster.cg - profiles vs_1_1 arbvp1 - entry_point main_vp - - default_params - { - param_named_auto wvpMat worldviewproj_matrix - } -} - -fragment_program depth_shadow_caster_ps cg -{ - source depthshadowcaster.cg - profiles ps_2_0 arbfp1 - entry_point main_fp - - default_params - { - } -} - -fragment_program depth_shadow_caster_ps_noalpha cg -{ - source depthshadowcaster.cg - profiles ps_2_0 arbfp1 - entry_point main_fp_noalpha - - default_params - { - } -} - -material depth_shadow_caster -{ - technique - { - pass - { - // force-disable fog (relevant for DirectX profiles below SM3 that always apply fixed function fog) - fog_override true - - vertex_program_ref depth_shadow_caster_vs - { - } - - fragment_program_ref depth_shadow_caster_ps - { - } - } - } -} - -material depth_shadow_caster_noalpha -{ - technique - { - pass - { - // force-disable fog (relevant for DirectX profiles below SM3 that always apply fixed function fog) - fog_override true - - vertex_program_ref depth_shadow_caster_vs - { - } - - fragment_program_ref depth_shadow_caster_ps_noalpha - { - } - } - } -} diff --git a/files/water/WaterNormal2.tga b/files/water/WaterNormal2.tga deleted file mode 100644 index 771d15041..000000000 Binary files a/files/water/WaterNormal2.tga and /dev/null differ diff --git a/files/water/caustic_0.png b/files/water/caustic_0.png deleted file mode 100644 index fee464860..000000000 Binary files a/files/water/caustic_0.png and /dev/null differ diff --git a/files/water/perlinvolume.dds b/files/water/perlinvolume.dds deleted file mode 100644 index bd8147d49..000000000 Binary files a/files/water/perlinvolume.dds and /dev/null differ diff --git a/files/water/underwater.cg b/files/water/underwater.cg deleted file mode 100644 index b853dd535..000000000 --- a/files/water/underwater.cg +++ /dev/null @@ -1,61 +0,0 @@ -void main_vp -( - in float4 inPos : POSITION, - - out float4 pos : POSITION, - out float2 uv0 : TEXCOORD0, - out float4 noiseCoord : TEXCOORD1, - - uniform float4x4 worldViewProj, - uniform float timeVal, - uniform float scale -) -{ - // Use standardise transform, so work accord with render system specific (RS depth, requires texture flipping, etc) - pos = mul(worldViewProj, inPos); - - // The input positions adjusted by texel offsets, so clean up inaccuracies - inPos.xy = sign(inPos.xy); - - // Convert to image-space - uv0 = (float2(inPos.x, -inPos.y) + 1.0f) * 0.5f; - noiseCoord = (pos + timeVal) * scale; -} - - - -float4 main_fp_nomrt (float2 iTexCoord : TEXCOORD0, - float3 noiseCoord : TEXCOORD1, - uniform sampler2D RT : register(s0), - uniform sampler2D NormalMap : register(s1), - uniform sampler2D CausticMap : register(s2), - uniform float4 tintColour) : COLOR -{ - float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; - - return tex2D(RT, iTexCoord + normal.xy * 0.015) + - (tex2D(CausticMap, noiseCoord) / 5) + - tintColour ; -} - - -float4 main_fp (float2 iTexCoord : TEXCOORD0, - float3 noiseCoord : TEXCOORD1, - uniform float far, - uniform sampler2D RT : register(s0), - uniform sampler2D NormalMap : register(s1), - uniform sampler2D CausticMap : register(s2), - uniform sampler2D DepthMap : register(s3), - uniform float4 tintColour) : COLOR -{ - float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1; - - float depth = tex2D(DepthMap, iTexCoord + normal.xy * 0.015).r * far; - depth = saturate(depth / 2000.f); - - float4 color = tex2D(RT, iTexCoord + normal.xy * 0.015) + - (tex2D(CausticMap, noiseCoord) / 5) + - tintColour; - - return lerp(color, float4(0, 0.65, 0.65, 1), depth); -} diff --git a/files/water/underwater_dome.mesh b/files/water/underwater_dome.mesh new file mode 100644 index 000000000..64ca569c2 Binary files /dev/null and b/files/water/underwater_dome.mesh differ diff --git a/files/water/water.cg b/files/water/water.cg deleted file mode 100644 index bf6d04c5c..000000000 --- a/files/water/water.cg +++ /dev/null @@ -1,121 +0,0 @@ -void main_vp -( - in float4 iPos : POSITION - , in float2 iUv : TEXCOORD0 - - , out float4 oPos : POSITION - , out float3 oScreenCoords : TEXCOORD0 - , out float2 oUv : TEXCOORD1 - , out float oDepth : TEXCOORD2 - , out float4 oEyeVector : TEXCOORD3 - - , uniform float4x4 wvpMat - , uniform float4 camPosObjSpace -) -{ - oPos = mul(wvpMat, iPos); - - oUv = iUv * 10; // uv scale - oDepth = oPos.z; - - float4x4 scalemat = float4x4( 0.5, 0, 0, 0.5, - 0, -0.5, 0, 0.5, - 0, 0, 0.5, 0.5, - 0, 0, 0, 1 ); - float4 texcoordProj = mul(scalemat, oPos); - oScreenCoords = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w); - - oEyeVector = camPosObjSpace - iPos; -} - -void main_fp -( - out float4 oColor : COLOR - - , in float3 iScreenCoords : TEXCOORD0 - , in float2 iUv : TEXCOORD1 - , in float iDepth : TEXCOORD2 - , in float4 iEyeVector : TEXCOORD3 - , uniform float renderTargetFlipping - , uniform float4 lightPosObjSpace0 - , uniform float4 lightSpecularColour0 - - , uniform sampler2D reflectionMap : register(s0) - , uniform sampler2D refractionMap : register(s1) - , uniform sampler2D depthMap : register(s2) - , uniform sampler2D normalMap : register(s3) - , uniform float time - , uniform float far - , uniform float4 fogParams - , uniform float4 fogColour - , uniform float isUnderwater -) -{ - - float2 screenCoords = iScreenCoords.xy / iScreenCoords.z; - screenCoords.y = (1-saturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; - - // No need for transparency since we are using a refraction map - oColor.a = 1; - - // Sample screen-space depth map and subtract pixel depth to get the real water depth - float depthTex = tex2D(depthMap, screenCoords).r; - float depth1 = depthTex * far - iDepth; - depth1 = saturate(depth1 / 500.f); - - // Simple wave effect. to be replaced by something better - float2 uv1 = iUv + time * float2(0.5, 0); - float2 uv2 = iUv + time * float2(0, 0.5); - float2 uv3 = iUv + time * float2(-0.5, 0); - float2 uv4 = iUv + time * float2(0, -0.5); - float4 normal = tex2D(normalMap, uv1) + tex2D(normalMap, uv2) + tex2D(normalMap, uv3) + tex2D(normalMap, uv4); - normal = normal / 4.f; - normal = 2*normal - 1; - - float2 screenCoords_reflect = screenCoords + normal.yx * 0.05; - float2 screenCoords_refract = screenCoords + normal.yx * 0.05 * depth1; - - // Sample depth again with the refracted coordinates - depthTex = tex2D(depthMap, screenCoords_refract).r; - float depth2 = (depthTex * far - iDepth) / 500.f; - depth2 = (depthTex == 0 ? 1 : depth2); - // if depth2 is less than 0, this means we would refract something which is above water, - // which we don't want to - so in that case, don't refract - if (depth2 < 0.25) // delta due to inaccuracies - { - screenCoords_refract = screenCoords; - depth2 = depth1; - } - depth2 = saturate(depth2); - - float4 reflection = tex2D(reflectionMap, screenCoords_reflect); - float4 refraction = tex2D(refractionMap, screenCoords_refract); - - // tangent to object space - normal.xyz = normal.xzy; - - iEyeVector.xyz = normalize(iEyeVector.xyz); - - // fresnel - float facing = 1.0 - max(abs(dot(iEyeVector.xyz, normal.xyz)), 0); - float reflectionFactor = saturate(0.35 + 0.65 * pow(facing, 2)); - - // specular - float3 lightDir = normalize(lightPosObjSpace0.xyz); // assumes that light 0 is a directional light - float3 halfVector = normalize(iEyeVector + lightDir); - float specular = pow(max(dot(normal.xyz, halfVector.xyz), 0), 64); - - float opacity = depth2 * saturate(reflectionFactor + specular); - opacity *= (1-isUnderwater); - - reflection.xyz += lightSpecularColour0.xyz * specular; - - oColor.xyz = lerp(refraction.xyz, reflection.xyz, opacity); - - oColor.xyz += isUnderwater * float3(0, 0.35, 0.35); // underwater tint color - oColor.xyz = lerp(oColor.xyz, float3(0, 0.65, 0.65), saturate(isUnderwater * (iDepth / 2000.f))); // underwater fog - - // add fog - //float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); - //oColor.xyz = lerp(oColor.xyz, fogColour, fogValue); -} diff --git a/files/water/water.compositor b/files/water/water.compositor deleted file mode 100644 index 8d9c3cb39..000000000 --- a/files/water/water.compositor +++ /dev/null @@ -1,46 +0,0 @@ -compositor UnderwaterNoMRT -{ - technique - { - texture rt0 target_width target_height PF_R8G8B8 - - target rt0 { input previous } - - target_output - { - // Start with clear output - input none - - pass render_quad - { - material Water/CompositorNoMRT - input 0 rt0 - } - } - } -} - - -compositor Underwater -{ - technique - { - texture_ref scene gbuffer mrt_output - texture rt0 target_width target_height PF_R8G8B8 - - target rt0 { input previous } - - target_output - { - // Start with clear output - input none - - pass render_quad - { - material Water/Compositor - input 0 rt0 - input 3 scene 1 - } - } - } -} diff --git a/files/water/water.material b/files/water/water.material deleted file mode 100644 index a2a6b3e2d..000000000 --- a/files/water/water.material +++ /dev/null @@ -1,223 +0,0 @@ -vertex_program UnderwaterEffectVP cg -{ - source underwater.cg - entry_point main_vp - profiles vs_1_1 arbvp1 - - default_params - { - param_named_auto worldViewProj worldviewproj_matrix - } -} - - -fragment_program UnderwaterEffectFP_NoMRT cg -{ - source underwater.cg - entry_point main_fp_nomrt - profiles ps_2_0 arbfp1 -} - -fragment_program UnderwaterEffectFP cg -{ - source underwater.cg - entry_point main_fp - profiles ps_2_0 arbfp1 -} - -vertex_program Water_VP cg -{ - source water.cg - entry_point main_vp - profiles vs_2_x arbvp1 - - default_params - { - param_named_auto wvpMat worldviewproj_matrix - } -} - -fragment_program Water_FP cg -{ - source water.cg - entry_point main_fp - profiles ps_2_x arbfp1 -} - -material Water -{ - technique - { - pass - { - cull_hardware none - - vertex_program_ref Water_VP - { - param_named_auto camPosObjSpace camera_position_object_space - } - fragment_program_ref Water_FP - { - param_named_auto time time 0.1 - //param_named_auto fogColour fog_colour - //param_named_auto fogParams fog_params - param_named_auto renderTargetFlipping render_target_flipping - param_named_auto far far_clip_distance - param_named_auto lightPosObjSpace0 light_position_object_space 0 - param_named_auto lightSpecularColour0 light_specular_colour 0 - param_named isUnderwater float 0 - } - - texture_unit reflectionMap - { - texture WaterReflection - tex_address_mode clamp - } - - texture_unit refractionMap - { - tex_address_mode clamp - } - - texture_unit depthMap - { - tex_address_mode clamp - } - - texture_unit normalMap - { - texture WaterNormal2.tga - } - } - } - - technique - { - scheme Fallback - pass - { - cull_hardware none - scene_blend alpha_blend - depth_write off - diffuse 0 0 0 1 - emissive 0.6 0.7 1.0 - ambient 0 0 0 - texture_unit - { - // texture names set via code - scale 0.1 0.1 - alpha_op_ex source1 src_manual src_current 0.7 - } - } - } - -} - -material Water_Fallback -{ - technique - { - scheme Fallback - pass - { - cull_hardware none - scene_blend alpha_blend - depth_write off - diffuse 0 0 0 1 - emissive 0.6 0.7 1.0 - ambient 0 0 0 - texture_unit - { - // texture names set via code - scale 0.1 0.1 - alpha_op_ex source1 src_manual src_current 0.7 - } - } - } -} - -material Water/CompositorNoMRT -{ - technique - { - pass - { - depth_check off - vertex_program_ref UnderwaterEffectVP - { - param_named_auto timeVal time 0.25 - param_named scale float 0.1 - } - - fragment_program_ref UnderwaterEffectFP_NoMRT - { - param_named tintColour float4 0 0.35 0.35 1 - } - - texture_unit RT - { - tex_coord_set 0 - tex_address_mode clamp - filtering linear linear linear - } - - texture_unit - { - texture WaterNormal2.tga 2d - tex_coord_set 1 - //tex_address_mode clamp - filtering linear linear linear - } - texture_unit - { - texture caustic_0.png 2d - tex_coord_set 2 - //tex_address_mode clamp - filtering linear linear linear - } - } - } -} - -material Water/Compositor -{ - technique - { - pass - { - depth_check off - vertex_program_ref UnderwaterEffectVP - { - param_named_auto timeVal time 0.25 - param_named scale float 0.1 - } - - fragment_program_ref UnderwaterEffectFP - { - param_named tintColour float4 0 0.35 0.35 1 - param_named_auto far far_clip_distance - } - - texture_unit RT - { - tex_coord_set 0 - tex_address_mode clamp - } - - texture_unit - { - texture WaterNormal2.tga 2d - tex_coord_set 2 - } - texture_unit - { - texture caustic_0.png 2d - tex_coord_set 3 - } - - texture_unit DepthMap - { - } - } - } -} diff --git a/files/water/water_nm.png b/files/water/water_nm.png new file mode 100644 index 000000000..361431a0e Binary files /dev/null and b/files/water/water_nm.png differ diff --git a/libs/mangle/input/servers/ois_driver.cpp b/libs/mangle/input/servers/ois_driver.cpp index b8e4f5eb9..07ba3e83a 100644 --- a/libs/mangle/input/servers/ois_driver.cpp +++ b/libs/mangle/input/servers/ois_driver.cpp @@ -1,6 +1,6 @@ #include "ois_driver.hpp" -#include +#include #include #include #include diff --git a/libs/mangle/rend2d/servers/sdl_driver.cpp b/libs/mangle/rend2d/servers/sdl_driver.cpp index aa1ff6c6d..84a17933f 100644 --- a/libs/mangle/rend2d/servers/sdl_driver.cpp +++ b/libs/mangle/rend2d/servers/sdl_driver.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include using namespace Mangle::Rend2D; diff --git a/libs/mangle/rend2d/servers/sdl_gl_driver.cpp b/libs/mangle/rend2d/servers/sdl_gl_driver.cpp index 2bcb1d677..db519e091 100644 --- a/libs/mangle/rend2d/servers/sdl_gl_driver.cpp +++ b/libs/mangle/rend2d/servers/sdl_gl_driver.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include using namespace Mangle::Rend2D; diff --git a/libs/mangle/stream/clients/audiere_file.cpp b/libs/mangle/stream/clients/audiere_file.cpp deleted file mode 100644 index 16bc7891a..000000000 --- a/libs/mangle/stream/clients/audiere_file.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "audiere_file.hpp" - -using namespace audiere; -using namespace Mangle::Stream; - -bool AudiereFile::seek(int pos, SeekMode mode) -{ - assert(inp->isSeekable); - assert(inp->hasPosition); - - size_t newPos; - - switch(mode) - { - case BEGIN: newPos = pos; break; - case CURRENT: newPos = pos+tell(); break; - case END: - // Seeking from the end. This requires that we're able to get - // the entire size of the stream. The pos also has to be - // non-positive. - assert(inp->hasSize); - assert(pos <= 0); - newPos = inp->size() + pos; - break; - default: - assert(0 && "invalid seek mode"); - } - - inp->seek(newPos); - return inp->tell() == newPos; - -} diff --git a/libs/mangle/stream/clients/audiere_file.hpp b/libs/mangle/stream/clients/audiere_file.hpp deleted file mode 100644 index 61e26f21b..000000000 --- a/libs/mangle/stream/clients/audiere_file.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef MANGLE_STREAM_AUDIERECLIENT_H -#define MANGLE_STREAM_AUDIERECLIENT_H - -#include -#include - -#include "../stream.hpp" - -namespace Mangle { -namespace Stream { - -/** @brief An Audiere::File that wraps a Mangle::Stream input. - - This lets Audiere read sound files from any generic archive or - file manager that supports Mangle streams. - */ -class AudiereFile : public audiere::RefImplementation -{ - StreamPtr inp; - - public: - AudiereFile(StreamPtr _inp) - : inp(_inp) {} - - /// Read 'count' bytes, return bytes successfully read - int ADR_CALL read(void *buf, int count) - { return inp->read(buf,count); } - - /// Seek, relative to specified seek mode. Returns true if successful. - bool ADR_CALL seek(int pos, audiere::File::SeekMode mode); - - /// Get current position - int ADR_CALL tell() - { assert(inp->hasPosition); return inp->tell(); } -}; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/clients/io_stream.cpp b/libs/mangle/stream/clients/io_stream.cpp deleted file mode 100644 index 5f1edc221..000000000 --- a/libs/mangle/stream/clients/io_stream.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "io_stream.hpp" - -// This seems to work -#ifndef EOF -#define EOF -1 -#endif - -using namespace Mangle::Stream; - -#define BSIZE 1024 - -// Streambuf for normal stream reading -class _istreambuf : public std::streambuf -{ - StreamPtr client; - char buf[BSIZE]; - -public: - _istreambuf(StreamPtr strm) : client(strm) - { - // Make sure we picked the right class - assert(client->isReadable); - assert(!client->hasPtr); - - // Tell streambuf to delegate reading operations to underflow() - setg(NULL,NULL,NULL); - - // Disallow writing - setp(NULL,NULL); - } - - /* Underflow is called when there is no more info to read in the - input buffer. We need to refill buf with new data (if any), and - set up the internal pointers with setg() to reflect the new - state. - */ - int underflow() - { - // Read some more data - size_t read = client->read(buf, BSIZE); - assert(read <= BSIZE); - - // If we're out of data, then EOF - if(read == 0) - return EOF; - - // Otherwise, set up input buffer - setg(buf, buf, buf+read); - - // Return the first char - return *((unsigned char*)buf); - } - - // Seek stream, if the source supports it. Ignores the second - // parameter as Mangle doesn't separate input and output pointers. - std::streampos seekpos(std::streampos pos, std::ios_base::openmode = std::ios_base::in) - { - // Does this stream know how to seek? - if(!client->isSeekable || !client->hasPosition) - // If not, signal an error. - return -1; - - // Set stream position and reset the buffer. - client->seek(pos); - setg(NULL,NULL,NULL); - - return client->tell(); - } -}; - -// Streambuf optimized for pointer-based input streams -class _ptrstreambuf : public std::streambuf -{ - StreamPtr client; - -public: - _ptrstreambuf(StreamPtr strm) : client(strm) - { - // Make sure we picked the right class - assert(client->isReadable); - assert(client->hasPtr); - - // seekpos() does all the work - seekpos(0); - } - - // Underflow is only called when we're at the end of the file - int underflow() { return EOF; } - - // Seek to a new position within the memory stream. This bypasses - // client->seek() entirely so isSeekable doesn't have to be set. - std::streampos seekpos(std::streampos pos, std::ios_base::openmode = std::ios_base::in) - { - // All pointer streams need a size - assert(client->hasSize); - - // Figure out how much will be left of the stream after seeking - size_t size = client->size() - pos; - - // Get a pointer - char* ptr = (char*)client->getPtr(pos,size); - - // And use it - setg(ptr,ptr,ptr+size); - - return pos; - } -}; - -// Streambuf for stream writing -class _ostreambuf : public std::streambuf -{ - StreamPtr client; - char buf[BSIZE]; - -public: - _ostreambuf(StreamPtr strm) : client(strm) - { - // Make sure we picked the right class - assert(client->isWritable); - - // Inform streambuf about our nice buffer - setp(buf, buf+BSIZE); - - // Disallow reading - setg(NULL,NULL,NULL); - } - - /* Sync means to flush (write) all current data to the output - stream. It will also set up the entire output buffer to be usable - again. - */ - int sync() - { - // Get the number of bytes that streambuf wants us to write - int num = pptr() - pbase(); - assert(num >= 0); - - // Is there any work to do? - if(num == 0) return 0; - - if((int)client->write(pbase(), num) != num) - // Inform caller that writing failed - return -1; - - // Reset output buffer pointers - setp(buf, buf+BSIZE); - - // No error - return 0; - } - - /* Called whenever the output buffer is full. - */ - int overflow(int c) - { - // First, write all existing data - if(sync()) return EOF; - - // Put the requested character in the next round of output - if(c != EOF) - { - *pptr() = c; - pbump(1); - } - - // No error - return 0; - } - - // Seek stream, if the source supports it. - std::streampos seekpos(std::streampos pos, std::ios_base::openmode = std::ios_base::out) - { - if(!client->isSeekable || !client->hasPosition) - return -1; - - // Flush data and reset buffers - sync(); - - // Set stream position - client->seek(pos); - - return client->tell(); - } -}; - -MangleIStream::MangleIStream(StreamPtr inp) - : std::istream(NULL) -{ - assert(inp->isReadable); - - // Pick the right streambuf implementation based on whether the - // input supports pointers or not. - if(inp->hasPtr) - buf = new _ptrstreambuf(inp); - else - buf = new _istreambuf(inp); - - rdbuf(buf); -} - -MangleIStream::~MangleIStream() -{ - delete buf; -} - -MangleOStream::MangleOStream(StreamPtr out) - : std::ostream(NULL) -{ - assert(out->isWritable); - buf = new _ostreambuf(out); - - rdbuf(buf); -} - -MangleOStream::~MangleOStream() -{ - // Make sure we don't have lingering data on exit - flush(); - delete buf; -} diff --git a/libs/mangle/stream/clients/io_stream.hpp b/libs/mangle/stream/clients/io_stream.hpp deleted file mode 100644 index 98c6252ed..000000000 --- a/libs/mangle/stream/clients/io_stream.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef MANGLE_STREAM_IOSTREAM_H -#define MANGLE_STREAM_IOSTREAM_H - -#include -#include "../stream.hpp" -#include - -namespace Mangle { -namespace Stream { - - /** This file contains classes for wrapping an std::istream or - std::ostream around a Mangle::Stream. - - This allows you to use Mangle streams in places that require std - streams. - - This is much easier than trying to make your own custom streams - into iostreams. The std::iostream interface is horrible and NOT - designed for easy subclassing. Create a Mangle::Stream instead, - and use this wrapper. - */ - - // An istream wrapping a readable Mangle::Stream. Has extra - // optimizations for pointer-based streams. - class MangleIStream : public std::istream - { - std::streambuf *buf; - public: - MangleIStream(StreamPtr inp); - ~MangleIStream(); - }; - - // An ostream wrapping a writable Mangle::Stream. - class MangleOStream : public std::ostream - { - std::streambuf *buf; - public: - MangleOStream(StreamPtr inp); - ~MangleOStream(); - }; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/clients/ogre_datastream.hpp b/libs/mangle/stream/clients/ogre_datastream.hpp deleted file mode 100644 index 76a6f20cf..000000000 --- a/libs/mangle/stream/clients/ogre_datastream.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef MANGLE_STREAM_OGRECLIENT_H -#define MANGLE_STREAM_OGRECLIENT_H - -#include -#include -#include "../stream.hpp" - -namespace Mangle { -namespace Stream { - -/** An OGRE DataStream that wraps a Mangle::Stream input. - - This has been built and tested against OGRE 1.6.2. You might have - to make your own modifications if you're working with newer (or - older) versions. - */ -class Mangle2OgreStream : public Ogre::DataStream -{ - StreamPtr inp; - - void init() - { - // Get the size, if possible - if(inp->hasSize) - mSize = inp->size(); - - // Allow writing if inp supports it - if(inp->isWritable) - mAccess |= Ogre::DataStream::WRITE; - } - - public: - /// Constructor without name - Mangle2OgreStream(StreamPtr _inp) - : inp(_inp) { init(); } - - /// Constructor for a named data stream - Mangle2OgreStream(const Ogre::String &name, StreamPtr _inp) - : Ogre::DataStream(name), inp(_inp) { init(); } - - // Only implement the DataStream functions we have to implement - - size_t read(void *buf, size_t count) - { return inp->read(buf,count); } - - size_t write(const void *buf, size_t count) - { assert(inp->isWritable); return inp->write(buf,count); } - - void skip(long count) - { - assert(inp->isSeekable && inp->hasPosition); - inp->seek(inp->tell() + count); - } - - void seek(size_t pos) - { assert(inp->isSeekable); inp->seek(pos); } - - size_t tell() const - { assert(inp->hasPosition); return inp->tell(); } - - bool eof() const { return inp->eof(); } - - /// Does nothing - void close() {} -}; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/filters/buffer_stream.hpp b/libs/mangle/stream/filters/buffer_stream.hpp deleted file mode 100644 index f037212a3..000000000 --- a/libs/mangle/stream/filters/buffer_stream.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef MANGLE_STREAM_BUFFER_H -#define MANGLE_STREAM_BUFFER_H - -#include "../servers/memory_stream.hpp" -#include - -namespace Mangle { -namespace Stream { - -/** A Stream that reads another Stream into a buffer, and serves it as - a MemoryStream. Might be expanded with other capabilities later. - */ - -class BufferStream : public MemoryStream -{ - std::vector buffer; - - public: - /* - input = stream to copy - ADD = each read increment (for streams without size()) - */ - BufferStream(StreamPtr input, size_t ADD = 32*1024) - { - assert(input); - - // Allocate memory, read the stream into it. Then call set() - if(input->hasSize) - { - // We assume that we can get the position as well - assert(input->hasPosition); - - // Calculate how much is left of the stream - size_t left = input->size() - input->tell(); - - // Allocate the buffer and fill it - buffer.resize(left); - input->read(&buffer[0], left); - } - else - { - // We DON'T know how big the stream is. We'll have to read - // it in increments. - size_t len=0, newlen; - - while(!input->eof()) - { - // Read one block - newlen = len + ADD; - buffer.resize(newlen); - size_t read = input->read(&buffer[len], ADD); - - // Increase the total length - len += read; - - // If we read less than expected, we should be at the - // end of the stream - assert(read == ADD || (read < ADD && input->eof())); - } - - // Downsize to match the real length - buffer.resize(len); - } - - // After the buffer has been filled, set up our MemoryStream - // ancestor to reference it. - set(&buffer[0], buffer.size()); - } -}; - -typedef boost::shared_ptr BufferStreamPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/filters/pure_filter.hpp b/libs/mangle/stream/filters/pure_filter.hpp deleted file mode 100644 index f0ce91f87..000000000 --- a/libs/mangle/stream/filters/pure_filter.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef MANGLE_STREAM_FILTER_H -#define MANGLE_STREAM_FILTER_H - -#include "../stream.hpp" - -namespace Mangle { -namespace Stream { - -/** A stream that filters another stream with no changes. Intended as - a base class for other filters. - */ -class PureFilter : public Stream -{ - protected: - StreamPtr src; - - public: - PureFilter() {} - PureFilter(StreamPtr _src) - { setStream(_src); } - - void setStream(StreamPtr _src) - { - src = _src; - isSeekable = src->isSeekable; - isWritable = src->isWritable; - hasPosition = src->hasPosition; - hasSize = src->hasSize; - hasPtr = src->hasPtr; - } - - size_t read(void *buf, size_t count) { return src->read(buf, count); } - size_t write(const void *buf, size_t count) { return src->write(buf,count); } - void flush() { src->flush(); } - void seek(size_t pos) { src->seek(pos); } - size_t tell() const { return src->tell(); } - size_t size() const { return src->size(); } - bool eof() const { return src->eof(); } - const void *getPtr() { return src->getPtr(); } - const void *getPtr(size_t size) { return src->getPtr(size); } - const void *getPtr(size_t pos, size_t size) - { return src->getPtr(pos, size); } -}; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/filters/slice_stream.hpp b/libs/mangle/stream/filters/slice_stream.hpp deleted file mode 100644 index 6337b9d57..000000000 --- a/libs/mangle/stream/filters/slice_stream.hpp +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef MANGLE_STREAM_SLICE_H -#define MANGLE_STREAM_SLICE_H - -#include "../stream.hpp" - -namespace Mangle { -namespace Stream { - -/** A Stream that represents a subset (called a slice) of another stream. - */ -class SliceStream : public Stream -{ - StreamPtr src; - size_t offset, length, pos; - - public: - SliceStream(StreamPtr _src, size_t _offset, size_t _length) - : src(_src), offset(_offset), length(_length), pos(0) - { - assert(src->hasSize); - assert(src->isSeekable); - - // Make sure we can actually fit inside the source stream - assert(src->size() >= offset+length); - - isSeekable = true; - hasPosition = true; - hasSize = true; - hasPtr = src->hasPtr; - isWritable = src->isWritable; - } - - size_t read(void *buf, size_t count) - { - // Check that we're not reading past our slice - if(count > length-pos) - count = length-pos; - - // Seek into place and start reading - src->seek(offset+pos); - count = src->read(buf, count); - - pos += count; - assert(pos <= length); - return count; - } - - // Note that writing to a slice does not allow you to append data, - // you may only overwrite existing data. - size_t write(const void *buf, size_t count) - { - assert(isWritable); - // Check that we're not reading past our slice - if(count > length-pos) - count = length-pos; - - // Seek into place and action - src->seek(offset+pos); - count = src->write(buf, count); - - pos += count; - assert(pos <= length); - return count; - } - - void seek(size_t _pos) - { - pos = _pos; - if(pos > length) pos = length; - } - - bool eof() const { return pos == length; } - size_t tell() const { return pos; } - size_t size() const { return length; } - void flush() { src->flush(); } - - const void *getPtr() { return getPtr(0, length); } - const void *getPtr(size_t size) - { - const void *ptr = getPtr(pos, size); - seek(pos+size); - return ptr; - } - const void *getPtr(size_t pos, size_t size) - { - // Boundry checks on pos and size. Bounding the size is - // important even when getting pointers, as the source stream - // may use the size parameter for something (such as memory - // mapping or buffering.) - if(pos > length) pos = length; - if(pos+size > length) size = length-pos; - - // Ask the source to kindly give us a pointer - return src->getPtr(offset+pos, size); - } -}; - -typedef boost::shared_ptr SliceStreamPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/servers/file_stream.hpp b/libs/mangle/stream/servers/file_stream.hpp deleted file mode 100644 index 314a49642..000000000 --- a/libs/mangle/stream/servers/file_stream.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef MANGLE_STREAM_FILESERVER_H -#define MANGLE_STREAM_FILESERVER_H - -#include "std_stream.hpp" -#include -#include - -namespace Mangle { -namespace Stream { - -/** Very simple file input stream, based on std::ifstream - */ -class FileStream : public StdStream -{ - std::ifstream file; - - public: - FileStream(const std::string &name) - : StdStream(&file) - { - file.open(name.c_str(), std::ios::binary); - - if(file.fail()) - throw std::runtime_error("FileStream: failed to open file " + name); - } - ~FileStream() { file.close(); } -}; - -typedef boost::shared_ptr FileStreamPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/servers/memory_stream.hpp b/libs/mangle/stream/servers/memory_stream.hpp deleted file mode 100644 index 0849e4a3c..000000000 --- a/libs/mangle/stream/servers/memory_stream.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef MANGLE_STREAM_MEMSERVER_H -#define MANGLE_STREAM_MEMSERVER_H - -#include -#include "../stream.hpp" -#include - -namespace Mangle { -namespace Stream { - -// Do this before the class declaration, since the class itself -// uses it. -class MemoryStream; -typedef boost::shared_ptr MemoryStreamPtr; - -/** A Stream wrapping a memory buffer - - This will create a fully seekable stream out of any pointer/length - pair you give it. - */ -class MemoryStream : public Stream -{ - const void *data; - size_t length, pos; - - public: - MemoryStream(const void *ptr, size_t len) - : data(ptr), length(len), pos(0) - { - isSeekable = true; - hasPosition = true; - hasSize = true; - hasPtr = true; - } - - MemoryStream() - : data(NULL), length(0), pos(0) - { - isSeekable = true; - hasPosition = true; - hasSize = true; - hasPtr = true; - } - - size_t read(void *buf, size_t count) - { - assert(data != NULL); - assert(pos <= length); - - // Don't read more than we have - if(count > (length - pos)) - count = length - pos; - - // Copy data - if(count) - memcpy(buf, ((char*)data)+pos, count); - - // aaand remember to increase the count - pos += count; - - return count; - } - - void seek(size_t _pos) - { - pos = _pos; - if(pos > length) - pos = length; - } - - size_t tell() const { return pos; } - size_t size() const { return length; } - bool eof() const { return pos == length; } - - const void *getPtr() { return data; } - const void *getPtr(size_t size) - { - // This variant of getPtr must move the position pointer - size_t opos = pos; - pos += size; - if(pos > length) pos = length; - return ((char*)data)+opos; - } - const void *getPtr(size_t pos, size_t size) - { - if(pos > length) pos = length; - return ((char*)data)+pos; - } - - // New members in MemoryStream: - - /// Set a new buffer and length. This will rewind the position to zero. - void set(const void* _data, size_t _length) - { - data = _data; - length = _length; - pos = 0; - } - - /// Clone this memory stream - /** Make a new stream of the same buffer. If setPos is true, we also - set the clone's position to be the same as ours. - - No memory is copied during this operation, the new stream is - just another 'view' into the same shared memory buffer. - */ - MemoryStreamPtr clone(bool setPos=false) const - { - MemoryStreamPtr res(new MemoryStream(data, length)); - if(setPos) res->seek(pos); - return res; - } -}; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/servers/ogre_datastream.hpp b/libs/mangle/stream/servers/ogre_datastream.hpp deleted file mode 100644 index a5be98c84..000000000 --- a/libs/mangle/stream/servers/ogre_datastream.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef MANGLE_STREAM_OGRESERVER_H -#define MANGLE_STREAM_OGRESERVER_H - -#include - -namespace Mangle { -namespace Stream { - -/** A Stream wrapping an OGRE DataStream. - - This has been built and tested against OGRE 1.6.2. You might have - to make your own modifications if you're working with newer (or - older) versions. - */ -class OgreStream : public Stream -{ - Ogre::DataStreamPtr inp; - - public: - OgreStream(Ogre::DataStreamPtr _inp) : inp(_inp) - { - isSeekable = true; - hasPosition = true; - hasSize = true; - } - - size_t read(void *buf, size_t count) { return inp->read(buf,count); } - void seek(size_t pos) { inp->seek(pos); } - size_t tell() const { return inp->tell(); } - size_t size() const { return inp->size(); } - bool eof() const { return inp->eof(); } -}; - -typedef boost::shared_ptr OgreStreamPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/servers/outfile_stream.hpp b/libs/mangle/stream/servers/outfile_stream.hpp deleted file mode 100644 index 8d953d904..000000000 --- a/libs/mangle/stream/servers/outfile_stream.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef MANGLE_OSTREAM_FILESERVER_H -#define MANGLE_OSTREAM_FILESERVER_H - -#include "std_ostream.hpp" -#include - -namespace Mangle { -namespace Stream { - -/** File stream based on std::ofstream, only supports writing. - */ -class OutFileStream : public StdOStream -{ - std::ofstream file; - - public: - /** - By default we overwrite the file. If append=true, then we will - open an existing file and seek to the end instead. - */ - OutFileStream(const std::string &name, bool append=false) - : StdOStream(&file) - { - std::ios::openmode mode = std::ios::binary; - if(append) - mode |= std::ios::app; - else - mode |= std::ios::trunc; - - file.open(name.c_str(), mode); - - if(file.fail()) - throw std::runtime_error("OutFileStream: failed to open file " + name); - } - ~OutFileStream() { file.close(); } -}; - -typedef boost::shared_ptr OutFileStreamPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/servers/phys_stream.hpp b/libs/mangle/stream/servers/phys_stream.hpp deleted file mode 100644 index 4312ac041..000000000 --- a/libs/mangle/stream/servers/phys_stream.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MANGLE_STREAM_OGRESERVER_H -#define MANGLE_STREAM_OGRESERVER_H - -#include - -namespace Mangle { -namespace Stream { - -/// A Stream wrapping a PHYSFS_file stream from the PhysFS library. -class PhysFile : public Stream -{ - PHYSFS_file *file; - - public: - PhysFile(PHYSFS_file *inp) : file(inp) - { - isSeekable = true; - hasPosition = true; - hasSize = true; - } - - ~PhysFile() { PHYSFS_close(file); } - - size_t read(void *buf, size_t count) - { return PHYSFS_read(file, buf, 1, count); } - - void seek(size_t pos) { PHYSFS_seek(file, pos); } - size_t tell() const { return PHYSFS_tell(file); } - size_t size() const { return PHYSFS_fileLength(file); } - bool eof() const { return PHYSFS_eof(file); } -}; - -typedef boost::shared_ptr PhysFilePtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/servers/std_ostream.hpp b/libs/mangle/stream/servers/std_ostream.hpp deleted file mode 100644 index f406e1a93..000000000 --- a/libs/mangle/stream/servers/std_ostream.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef MANGLE_OSTREAM_STDIOSERVER_H -#define MANGLE_OSTREAM_STDIOSERVER_H - -#include "../stream.hpp" -#include -#include - -namespace Mangle { -namespace Stream { - -/** Simple wrapper for std::ostream, only supports output. - */ -class StdOStream : public Stream -{ - std::ostream *inf; - - static void fail(const std::string &msg) - { throw std::runtime_error("StdOStream: " + msg); } - - public: - StdOStream(std::ostream *_inf) - : inf(_inf) - { - isSeekable = true; - hasPosition = true; - hasSize = true; - isWritable = true; - isReadable = false; - } - - size_t write(const void* buf, size_t len) - { - inf->write((const char*)buf, len); - if(inf->fail()) - fail("error writing to stream"); - // Just return len, but that is ok. The only cases where we would - // return less than len is when an error occured. - return len; - } - - void flush() - { - inf->flush(); - } - - void seek(size_t pos) - { - inf->seekp(pos); - if(inf->fail()) - fail("seek error"); - } - - size_t tell() const - // Hack around the fact that ifstream->tellp() isn't const - { return ((StdOStream*)this)->inf->tellp(); } - - size_t size() const - { - // Use the standard iostream size hack, terrible as it is. - std::streampos pos = inf->tellp(); - inf->seekp(0, std::ios::end); - size_t res = inf->tellp(); - inf->seekp(pos); - - if(inf->fail()) - fail("could not get stream size"); - - return res; - } - - bool eof() const - { return inf->eof(); } -}; - -typedef boost::shared_ptr StdOStreamPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/servers/std_stream.hpp b/libs/mangle/stream/servers/std_stream.hpp deleted file mode 100644 index 163f023f6..000000000 --- a/libs/mangle/stream/servers/std_stream.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef MANGLE_STREAM_STDIOSERVER_H -#define MANGLE_STREAM_STDIOSERVER_H - -#include "../stream.hpp" -#include -#include - -namespace Mangle { -namespace Stream { - -/** Simple wrapper for std::istream. - */ -class StdStream : public Stream -{ - std::istream *inf; - - static void fail(const std::string &msg) - { throw std::runtime_error("StdStream: " + msg); } - - public: - StdStream(std::istream *_inf) - : inf(_inf) - { - isSeekable = true; - hasPosition = true; - hasSize = true; - } - - size_t read(void* buf, size_t len) - { - inf->read((char*)buf, len); - if(inf->bad()) - fail("error reading from stream"); - return inf->gcount(); - } - - void seek(size_t pos) - { - inf->clear(); - inf->seekg(pos); - if(inf->fail()) - fail("seek error"); - } - - size_t tell() const - // Hack around the fact that ifstream->tellg() isn't const - { return ((StdStream*)this)->inf->tellg(); } - - size_t size() const - { - // Use the standard iostream size hack, terrible as it is. - std::streampos pos = inf->tellg(); - inf->seekg(0, std::ios::end); - size_t res = inf->tellg(); - inf->seekg(pos); - - if(inf->fail()) - fail("could not get stream size"); - - return res; - } - - bool eof() const - { return inf->eof(); } -}; - -typedef boost::shared_ptr StdStreamPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/stream.hpp b/libs/mangle/stream/stream.hpp deleted file mode 100644 index 2ee4fcbd8..000000000 --- a/libs/mangle/stream/stream.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef MANGLE_STREAM_INPUT_H -#define MANGLE_STREAM_INPUT_H - -#include -#include "../tools/shared_ptr.hpp" -#include - -namespace Mangle { -namespace Stream { - -/// An abstract interface for a stream data. -class Stream -{ - public: - // Feature options. These should be set in the constructor. - - /// If true, seek() works - bool isSeekable; - - /// If true, tell() works - bool hasPosition; - - /// If true, size() works - bool hasSize; - - /// If true, write() works. Writing through pointer operations is - /// not (yet) supported. - bool isWritable; - - /// If true, read() and eof() works. - bool isReadable; - - /// If true, the getPtr() functions work - bool hasPtr; - - /// Initialize all bools to false by default, except isReadable. - Stream() : - isSeekable(false), hasPosition(false), hasSize(false), - isWritable(false), isReadable(true), hasPtr(false) {} - - /// Virtual destructor - virtual ~Stream() {} - - /** Read a given number of bytes from the stream. Returns the actual - number read. If the return value is less than count, then the - stream is empty or an error occured. Only required for readable - streams. - */ - virtual size_t read(void* buf, size_t count) { assert(0); return 0; } - - /** Write a given number of bytes from the stream. Semantics is - similar to read(). Only valid if isWritable is true. - - The returned value is the number of bytes written. However in - most cases, unlike for read(), a write-count less than requested - usually indicates an error. The implementation should throw such - errors as exceptions rather than expect the caller to handle - them. - - Since most implementations do NOT support writing we default to - an assert(0) here. - */ - virtual size_t write(const void *buf, size_t count) { assert(0); return 0; } - - /// Flush an output stream. Does nothing for non-writing streams. - virtual void flush() {} - - /// Seek to an absolute position in this stream. Not all streams are - /// seekable. - virtual void seek(size_t pos) { assert(0); } - - /// Get the current position in the stream. Non-seekable streams are - /// not required to keep track of this. - virtual size_t tell() const { assert(0); return 0; } - - /// Return the total size of the stream. For streams hasSize is - /// false, size() should fail in some way, since it is an error to - /// call it in those cases. - virtual size_t size() const { assert(0); return 0; } - - /// Returns true if the stream is empty. Required for readable - /// streams. - virtual bool eof() const { assert(0); return 0; } - - /// Return a pointer to the entire stream. This function (and the - /// other getPtr() variants below) should only be implemented for - /// memory-based streams where using them would be an optimization. - virtual const void *getPtr() { assert(0); return NULL; } - - /// Get a pointer to a memory region of 'size' bytes starting from - /// position 'pos' - virtual const void *getPtr(size_t pos, size_t size) { assert(0); return NULL; } - - /// Get a pointer to a memory region of 'size' bytes from the - /// current position. Unlike the two other getPtr variants, this - /// will advance the position past the returned area. - virtual const void *getPtr(size_t size) { assert(0); return NULL; } -}; - -typedef boost::shared_ptr StreamPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/stream/tests/.gitignore b/libs/mangle/stream/tests/.gitignore deleted file mode 100644 index 9dfd618e2..000000000 --- a/libs/mangle/stream/tests/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*_test -test.file diff --git a/libs/mangle/stream/tests/Makefile b/libs/mangle/stream/tests/Makefile deleted file mode 100644 index 5f4397819..000000000 --- a/libs/mangle/stream/tests/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -GCC=g++ -I../ -Wall -Werror - -all: ogre_client_test audiere_client_test memory_server_test buffer_filter_test file_server_test slice_filter_test file_write_test iostream_test - -I_OGRE=$(shell pkg-config --cflags OGRE) -L_OGRE=$(shell pkg-config --libs OGRE) -L_AUDIERE=-laudiere - -ogre_client_test: ogre_client_test.cpp ../stream.hpp ../clients/ogre_datastream.hpp - $(GCC) $< -o $@ $(I_OGRE) $(L_OGRE) - -audiere_client_test: audiere_client_test.cpp ../stream.hpp ../clients/audiere_file.hpp ../clients/audiere_file.cpp - $(GCC) $< -o $@ ../clients/audiere_file.cpp $(L_AUDIERE) - -iostream_test: iostream_test.cpp ../clients/io_stream.cpp - $(GCC) $^ -o $@ - -file_server_test: file_server_test.cpp ../stream.hpp ../servers/file_stream.hpp ../servers/std_stream.hpp - $(GCC) $< -o $@ - -file_write_test: file_write_test.cpp ../stream.hpp ../servers/outfile_stream.hpp ../servers/std_ostream.hpp - $(GCC) $< -o $@ - -memory_server_test: memory_server_test.cpp ../stream.hpp ../servers/memory_stream.hpp - $(GCC) $< -o $@ - -buffer_filter_test: buffer_filter_test.cpp ../stream.hpp ../servers/memory_stream.hpp ../filters/buffer_stream.hpp - $(GCC) $< -o $@ - -slice_filter_test: slice_filter_test.cpp ../stream.hpp ../servers/memory_stream.hpp ../filters/slice_stream.hpp - $(GCC) $< -o $@ - -clean: - rm *_test diff --git a/libs/mangle/stream/tests/audiere_client_test.cpp b/libs/mangle/stream/tests/audiere_client_test.cpp deleted file mode 100644 index 82be569cc..000000000 --- a/libs/mangle/stream/tests/audiere_client_test.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "../servers/memory_stream.hpp" -#include "../clients/audiere_file.hpp" -#include -#include - -using namespace Mangle::Stream; -using namespace audiere; -using namespace std; - -int main() -{ - char str[12]; - memset(str, 0, 12); - StreamPtr inp(new MemoryStream("hello world", 11)); - FilePtr p(new AudiereFile(inp)); - cout << "pos=" << p->tell() << endl; - p->read(str, 2); - cout << "2 bytes: " << str << endl; - cout << "pos=" << p->tell() << endl; - p->seek(4, File::BEGIN); - cout << "pos=" << p->tell() << endl; - p->read(str, 3); - cout << "3 bytes: " << str << endl; - p->seek(-1, File::CURRENT); - cout << "pos=" << p->tell() << endl; - p->seek(-4, File::END); - cout << "pos=" << p->tell() << endl; - p->read(str, 4); - cout << "last 4 bytes: " << str << endl; - p->seek(0, File::BEGIN); - p->read(str, 11); - cout << "entire stream: " << str << endl; - return 0; -} diff --git a/libs/mangle/stream/tests/buffer_filter_test.cpp b/libs/mangle/stream/tests/buffer_filter_test.cpp deleted file mode 100644 index e53bda651..000000000 --- a/libs/mangle/stream/tests/buffer_filter_test.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -#include "../filters/buffer_stream.hpp" - -using namespace Mangle::Stream; -using namespace std; - -int main() -{ - StreamPtr orig (new MemoryStream("hello world", 11)); - StreamPtr inp (new BufferStream(orig)); - - cout << "Size: " << inp->size() << endl; - cout << "Pos: " << inp->tell() << "\nSeeking...\n"; - inp->seek(3); - cout << "Pos: " << inp->tell() << endl; - char data[12]; - memset(data, 0, 12); - cout << "Reading: " << inp->read(data, 4) << endl; - cout << "Four bytes: " << data << endl; - cout << "Eof: " << inp->eof() << endl; - cout << "Pos: " << inp->tell() << "\nSeeking again...\n"; - inp->seek(33); - cout << "Pos: " << inp->tell() << endl; - cout << "Eof: " << inp->eof() << "\nSeek to 6\n"; - inp->seek(6); - cout << "Eof: " << inp->eof() << endl; - cout << "Pos: " << inp->tell() << endl; - cout << "Over-reading: " << inp->read(data, 200) << endl; - cout << "Result: " << data << endl; - cout << "Eof: " << inp->eof() << endl; - cout << "Pos: " << inp->tell() << endl; - inp->seek(0); - cout << "Finally, reading the entire string: " << inp->read(data,11) << endl; - cout << "Result: " << data << endl; - cout << "Eof: " << inp->eof() << endl; - cout << "Pos: " << inp->tell() << endl; - - return 0; -} diff --git a/libs/mangle/stream/tests/file_server_test.cpp b/libs/mangle/stream/tests/file_server_test.cpp deleted file mode 100644 index 3e1e3cfa5..000000000 --- a/libs/mangle/stream/tests/file_server_test.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "../servers/file_stream.hpp" -#include - -using namespace Mangle::Stream; -using namespace std; - -int main() -{ - StreamPtr inp(new FileStream("file_server_test.cpp")); - - char buf[21]; - buf[20] = 0; - cout << "pos=" << inp->tell() << " eof=" << inp->eof() << endl; - inp->read(buf, 20); - cout << "First 20 bytes: " << buf << endl; - cout << "pos=" << inp->tell() << " eof=" << inp->eof() << endl; - return 0; -} diff --git a/libs/mangle/stream/tests/file_write_test.cpp b/libs/mangle/stream/tests/file_write_test.cpp deleted file mode 100644 index c6c61fcca..000000000 --- a/libs/mangle/stream/tests/file_write_test.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "../servers/outfile_stream.hpp" -#include - -using namespace Mangle::Stream; -using namespace std; - -void print(Stream &str) -{ - cout << "size=" << str.size() - << " pos=" << str.tell() - << " eof=" << str.eof() - << endl; -} - -int main() -{ - { - cout << "\nCreating file\n"; - OutFileStream out("test.file"); - print(out); - out.write("hello",5); - print(out); - } - - { - cout << "\nAppending to file\n"; - OutFileStream out("test.file", true); - print(out); - out.write(" again\n",7); - print(out); - } - - { - cout << "\nOverwriting file\n"; - OutFileStream out("test.file"); - print(out); - out.write("overwrite!\n",11); - print(out); - } - return 0; -} diff --git a/libs/mangle/stream/tests/iostream_test.cpp b/libs/mangle/stream/tests/iostream_test.cpp deleted file mode 100644 index 60648c6c5..000000000 --- a/libs/mangle/stream/tests/iostream_test.cpp +++ /dev/null @@ -1,176 +0,0 @@ -#include -#include "../clients/io_stream.hpp" -#include "../servers/memory_stream.hpp" - -using namespace Mangle::Stream; -using namespace std; - -void test1() -{ - cout << "Testing ASCII reading from memory:\n"; - StreamPtr input(new MemoryStream("hello you world you", 19)); - MangleIStream inp(input); - - string str; - while(!inp.eof()) - { - inp >> str; - cout << "Got: " << str << endl; - } -} - -class Dummy : public Stream -{ - int count; - -public: - - Dummy() : count(0) - { - } - - size_t read(void *ptr, size_t num) - { - char *p = (char*)ptr; - char *start = p; - for(; (count < 2560) && (p-start < (int)num); count++) - { - *p = count / 10; - p++; - } - return p-start; - } - - bool eof() const { return count == 2560; } -}; - -void test2() -{ - cout << "\nTesting binary reading from non-memory:\n"; - - StreamPtr input(new Dummy); - MangleIStream inp(input); - - int x = 0; - while(!inp.eof()) - { - unsigned char buf[5]; - inp.read((char*)buf,5); - - // istream doesn't set eof() until we read _beyond_ the end of - // the stream, so we need an extra check. - if(inp.gcount() == 0) break; - - /* - for(int i=0;i<5;i++) - cout << (int)buf[i] << " "; - cout << endl; - */ - - assert(buf[4] == buf[0]); - assert(buf[0] == x/2); - x++; - } - cout << " Done\n"; -} - -struct Dummy2 : Stream -{ - Dummy2() - { - isWritable = true; - isReadable = false; - } - - size_t write(const void *ptr, size_t num) - { - const char *p = (const char*)ptr; - cout << " Got: "; - for(unsigned i=0;iwrite("testing", 7); - - cout << " Running through MangleOStream:\n"; - MangleOStream out(output); - out << "hello"; - out << " - are you ok?"; - cout << " Flushing:\n"; - out.flush(); - - cout << " Writing a hell of a lot of characters:\n"; - for(int i=0; i<127; i++) - out << "xxxxxxxx"; // 127 * 8 = 1016 - out << "fffffff"; // +7 = 1023 - cout << " Just one more:\n"; - out << "y"; - cout << " And oooone more:\n"; - out << "z"; - - cout << " Flushing again:\n"; - out.flush(); - cout << " Writing some more and exiting:\n"; - out << "blah bleh blob"; -} - -struct Dummy3 : Stream -{ - int pos; - - Dummy3() : pos(0) - { - hasPosition = true; - isSeekable = true; - } - - size_t read(void*, size_t num) - { - cout << " Reading " << num << " bytes from " << pos << endl; - pos += num; - return num; - } - - void seek(size_t npos) { pos = npos; } - size_t tell() const { return pos; } -}; - -void test4() -{ - cout << "\nTesting seeking;\n"; - StreamPtr input(new Dummy3); - - cout << " Direct reading:\n"; - input->read(0,10); - input->read(0,5); - - MangleIStream inp(input); - - cout << " Reading from istream:\n"; - char buf[20]; - inp.read(buf, 20); - inp.read(buf, 20); - inp.read(buf, 20); - - cout << " Seeking to 30 and reading again:\n"; - inp.seekg(30); - inp.read(buf, 20); -} - -int main() -{ - test1(); - test2(); - test3(); - test4(); - return 0; -} diff --git a/libs/mangle/stream/tests/memory_server_test.cpp b/libs/mangle/stream/tests/memory_server_test.cpp deleted file mode 100644 index 24d3bb17e..000000000 --- a/libs/mangle/stream/tests/memory_server_test.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -#include "../servers/memory_stream.hpp" - -using namespace Mangle::Stream; -using namespace std; - -int main() -{ - Stream* inp = new MemoryStream("hello world\0", 12); - - cout << "Size: " << inp->size() << endl; - cout << "Pos: " << inp->tell() << "\nSeeking...\n"; - inp->seek(3); - cout << "Pos: " << inp->tell() << endl; - char data[12]; - memset(data, 0, 12); - cout << "Reading: " << inp->read(data, 4) << endl; - cout << "Four bytes: " << data << endl; - cout << "Eof: " << inp->eof() << endl; - cout << "Pos: " << inp->tell() << "\nSeeking again...\n"; - inp->seek(33); - cout << "Pos: " << inp->tell() << endl; - cout << "Eof: " << inp->eof() << "\nSeek to 6\n"; - inp->seek(6); - cout << "Eof: " << inp->eof() << endl; - cout << "Pos: " << inp->tell() << endl; - cout << "Over-reading: " << inp->read(data, 200) << endl; - cout << "Result: " << data << endl; - cout << "Eof: " << inp->eof() << endl; - cout << "Pos: " << inp->tell() << endl; - inp->seek(0); - cout << "Finally, reading the entire string: " << inp->read(data,11) << endl; - cout << "Result: " << data << endl; - cout << "Eof: " << inp->eof() << endl; - cout << "Pos: " << inp->tell() << endl; - - cout << "Entire stream from pointer: " << (char*)inp->getPtr() << endl; - - return 0; -} diff --git a/libs/mangle/stream/tests/ogre_client_test.cpp b/libs/mangle/stream/tests/ogre_client_test.cpp deleted file mode 100644 index c8d0442c0..000000000 --- a/libs/mangle/stream/tests/ogre_client_test.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "../servers/memory_stream.hpp" -#include "../clients/ogre_datastream.hpp" -#include - -using namespace Mangle::Stream; -using namespace Ogre; -using namespace std; - -int main() -{ - StreamPtr inp(new MemoryStream("hello world", 11)); - DataStreamPtr p(new Mangle2OgreStream("hello", inp)); - cout << "Name: " << p->getName() << endl; - cout << "As string: " << p->getAsString() << endl; - cout << "pos=" << p->tell() << " eof=" << p->eof() << endl; - p->seek(0); - cout << "pos=" << p->tell() << " eof=" << p->eof() << endl; - p->skip(5); - p->skip(-2); - cout << "pos=" << p->tell() << " eof=" << p->eof() << endl; - return 0; -} diff --git a/libs/mangle/stream/tests/output/audiere_client_test.out b/libs/mangle/stream/tests/output/audiere_client_test.out deleted file mode 100644 index 2130db9fd..000000000 --- a/libs/mangle/stream/tests/output/audiere_client_test.out +++ /dev/null @@ -1,9 +0,0 @@ -pos=0 -2 bytes: he -pos=2 -pos=4 -3 bytes: o w -pos=6 -pos=7 -last 4 bytes: orld -entire stream: hello world diff --git a/libs/mangle/stream/tests/output/buffer_filter_test.out b/libs/mangle/stream/tests/output/buffer_filter_test.out deleted file mode 100644 index 0ca252f25..000000000 --- a/libs/mangle/stream/tests/output/buffer_filter_test.out +++ /dev/null @@ -1,22 +0,0 @@ -Size: 11 -Pos: 0 -Seeking... -Pos: 3 -Reading: 4 -Four bytes: lo w -Eof: 0 -Pos: 7 -Seeking again... -Pos: 11 -Eof: 1 -Seek to 6 -Eof: 0 -Pos: 6 -Over-reading: 5 -Result: world -Eof: 1 -Pos: 11 -Finally, reading the entire string: 11 -Result: hello world -Eof: 1 -Pos: 11 diff --git a/libs/mangle/stream/tests/output/file_server_test.out b/libs/mangle/stream/tests/output/file_server_test.out deleted file mode 100644 index 240f066a3..000000000 --- a/libs/mangle/stream/tests/output/file_server_test.out +++ /dev/null @@ -1,3 +0,0 @@ -pos=0 eof=0 -First 20 bytes: #include "../servers -pos=20 eof=0 diff --git a/libs/mangle/stream/tests/output/file_write_test.out b/libs/mangle/stream/tests/output/file_write_test.out deleted file mode 100644 index 34b07c49f..000000000 --- a/libs/mangle/stream/tests/output/file_write_test.out +++ /dev/null @@ -1,12 +0,0 @@ - -Creating file -size=0 pos=0 eof=0 -size=5 pos=5 eof=0 - -Appending to file -size=5 pos=5 eof=0 -size=12 pos=12 eof=0 - -Overwriting file -size=0 pos=0 eof=0 -size=11 pos=11 eof=0 diff --git a/libs/mangle/stream/tests/output/iostream_test.out b/libs/mangle/stream/tests/output/iostream_test.out deleted file mode 100644 index b6da80c80..000000000 --- a/libs/mangle/stream/tests/output/iostream_test.out +++ /dev/null @@ -1,32 +0,0 @@ -Testing ASCII reading from memory: -Got: hello -Got: you -Got: world -Got: you - -Testing binary reading from non-memory: - Done - -Writing to dummy stream: - Pure dummy test: - Got: t e s t i n g - Running through MangleOStream: - Flushing: - Got: h e l l o - a r e y o u o k ? - Writing a hell of a lot of characters: - Just one more: - And oooone more: - Got: x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x f f f f f f f y - Flushing again: - Got: z - Writing some more and exiting: - Got: b l a h b l e h b l o b - -Testing seeking; - Direct reading: - Reading 10 bytes from 0 - Reading 5 bytes from 10 - Reading from istream: - Reading 1024 bytes from 15 - Seeking to 30 and reading again: - Reading 1024 bytes from 30 diff --git a/libs/mangle/stream/tests/output/memory_server_test.out b/libs/mangle/stream/tests/output/memory_server_test.out deleted file mode 100644 index 7cd9533e7..000000000 --- a/libs/mangle/stream/tests/output/memory_server_test.out +++ /dev/null @@ -1,23 +0,0 @@ -Size: 12 -Pos: 0 -Seeking... -Pos: 3 -Reading: 4 -Four bytes: lo w -Eof: 0 -Pos: 7 -Seeking again... -Pos: 12 -Eof: 1 -Seek to 6 -Eof: 0 -Pos: 6 -Over-reading: 6 -Result: world -Eof: 1 -Pos: 12 -Finally, reading the entire string: 11 -Result: hello world -Eof: 0 -Pos: 11 -Entire stream from pointer: hello world diff --git a/libs/mangle/stream/tests/output/ogre_client_test.out b/libs/mangle/stream/tests/output/ogre_client_test.out deleted file mode 100644 index 62cd14604..000000000 --- a/libs/mangle/stream/tests/output/ogre_client_test.out +++ /dev/null @@ -1,5 +0,0 @@ -Name: hello -As string: hello world -pos=11 eof=1 -pos=0 eof=0 -pos=3 eof=0 diff --git a/libs/mangle/stream/tests/output/slice_filter_test.out b/libs/mangle/stream/tests/output/slice_filter_test.out deleted file mode 100644 index 6d84704a7..000000000 --- a/libs/mangle/stream/tests/output/slice_filter_test.out +++ /dev/null @@ -1,36 +0,0 @@ - -Slice 1: --------- -Size: 6 -Pos: 0 -Seeking... -Reading 6 bytes -Result: hello -Pos: 6 -Eof: 1 -Seeking: -Pos: 2 -Eof: 0 -Reading 4 bytes -Result: llo -Pos: 6 -Eof: 1 -Entire stream as pointer: hello - -Slice 2: --------- -Size: 6 -Pos: 0 -Seeking... -Reading 6 bytes -Result: world -Pos: 6 -Eof: 1 -Seeking: -Pos: 2 -Eof: 0 -Reading 4 bytes -Result: rld -Pos: 6 -Eof: 1 -Entire stream as pointer: world diff --git a/libs/mangle/stream/tests/slice_filter_test.cpp b/libs/mangle/stream/tests/slice_filter_test.cpp deleted file mode 100644 index da90e24ad..000000000 --- a/libs/mangle/stream/tests/slice_filter_test.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -#include "../filters/slice_stream.hpp" -#include "../servers/memory_stream.hpp" - -using namespace Mangle::Stream; -using namespace std; - -void test(StreamPtr inp) -{ - cout << "Size: " << inp->size() << endl; - cout << "Pos: " << inp->tell() << "\nSeeking...\n"; - char data[6]; - memset(data, 0, 6); - cout << "Reading " << inp->read(data, 6) << " bytes\n"; - cout << "Result: " << data << endl; - cout << "Pos: " << inp->tell() << endl; - cout << "Eof: " << inp->eof() << endl; - inp->seek(2); - cout << "Seeking:\nPos: " << inp->tell() << endl; - cout << "Eof: " << inp->eof() << endl; - cout << "Reading " << inp->read(data, 6) << " bytes\n"; - cout << "Result: " << data << endl; - cout << "Pos: " << inp->tell() << endl; - cout << "Eof: " << inp->eof() << endl; - cout << "Entire stream as pointer: " << (char*)inp->getPtr() << endl; -} - -int main() -{ - StreamPtr orig (new MemoryStream("hello\0world\0", 12)); - StreamPtr slice1 (new SliceStream(orig,0,6)); - StreamPtr slice2 (new SliceStream(orig,6,6)); - - cout << "\nSlice 1:\n--------\n"; - test(slice1); - cout << "\nSlice 2:\n--------\n"; - test(slice2); - - return 0; -} diff --git a/libs/mangle/stream/tests/test.sh b/libs/mangle/stream/tests/test.sh deleted file mode 100755 index 2d07708ad..000000000 --- a/libs/mangle/stream/tests/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -make || exit - -mkdir -p output - -PROGS=*_test - -for a in $PROGS; do - if [ -f "output/$a.out" ]; then - echo "Running $a:" - ./$a | diff output/$a.out - - else - echo "Creating $a.out" - ./$a > "output/$a.out" - git add "output/$a.out" - fi -done diff --git a/libs/mangle/vfs/clients/ogre_archive.cpp b/libs/mangle/vfs/clients/ogre_archive.cpp deleted file mode 100644 index 2d3f7c520..000000000 --- a/libs/mangle/vfs/clients/ogre_archive.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "ogre_archive.hpp" - -#include "../../stream/clients/ogre_datastream.hpp" - -using namespace Mangle::VFS; -using namespace Mangle::Stream; - -Ogre::DataStreamPtr MangleArchive::open(const Ogre::String& filename) const -{ - return Ogre::DataStreamPtr(new Mangle2OgreStream - (filename, vfs->open(filename))); -} - -static void fill(Ogre::FileInfoList &out, FileInfoList &in) -{ - int size = in.size(); - out.resize(size); - - for(int i=0; ihasList); - FileInfoListPtr lst = vfs->list("", recursive, dirs); - Ogre::StringVector *res = new Ogre::StringVector; - - fill(*res, *lst); - - return Ogre::StringVectorPtr(res); -} - -Ogre::FileInfoListPtr MangleArchive::listFileInfo(bool recursive, bool dirs) -{ - assert(vfs->hasList); - FileInfoListPtr lst = vfs->list("", recursive, dirs); - Ogre::FileInfoList *res = new Ogre::FileInfoList; - - fill(*res, *lst); - - return Ogre::FileInfoListPtr(res); -} - -// Find functions will only work if vfs->hasFind is set. -Ogre::StringVectorPtr MangleArchive::find(const Ogre::String& pattern, - bool recursive, - bool dirs) -{ - assert(vfs->hasFind); - FileInfoListPtr lst = vfs->find(pattern, recursive, dirs); - Ogre::StringVector *res = new Ogre::StringVector; - - fill(*res, *lst); - - return Ogre::StringVectorPtr(res); -} - -Ogre::FileInfoListPtr MangleArchive::findFileInfo(const Ogre::String& pattern, - bool recursive, - bool dirs) -{ - assert(vfs->hasFind); - FileInfoListPtr lst = vfs->find(pattern, recursive, dirs); - Ogre::FileInfoList *res = new Ogre::FileInfoList; - - fill(*res, *lst); - - return Ogre::FileInfoListPtr(res); -} diff --git a/libs/mangle/vfs/clients/ogre_archive.hpp b/libs/mangle/vfs/clients/ogre_archive.hpp deleted file mode 100644 index 7b371c6ef..000000000 --- a/libs/mangle/vfs/clients/ogre_archive.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef MANGLE_VFS_OGRECLIENT_H -#define MANGLE_VFS_OGRECLIENT_H - -#include -#include -#include "../vfs.hpp" - -namespace Mangle { -namespace VFS { - -/** An OGRE Archive implementation that wraps a Mangle::VFS - filesystem. - - This has been built and tested against OGRE 1.6.2, and has been - extended for OGRE 1.7. You might have to make your own - modifications if you're working with newer (or older) versions. - */ -class MangleArchive : public Ogre::Archive -{ - VFSPtr vfs; - - public: - MangleArchive(VFSPtr _vfs, const std::string &name, - const std::string &archType = "Mangle") - : Ogre::Archive(name, archType) - , vfs(_vfs) - {} - - bool isCaseSensitive() const { return vfs->isCaseSensitive; } - - // These do nothing. You have to load / unload the archive in the - // constructor/destructor. - void load() {} - void unload() {} - - bool exists(const Ogre::String& filename) - { return vfs->isFile(filename); } - - time_t getModifiedTime(const Ogre::String& filename) - { return vfs->stat(filename)->time; } - - // With both these we support both OGRE 1.6 and 1.7 - Ogre::DataStreamPtr open(const Ogre::String& filename) const; - Ogre::DataStreamPtr open(const Ogre::String& filename, bool readOnly) const - { return open(filename); } - - Ogre::StringVectorPtr list(bool recursive = true, bool dirs = false); - Ogre::FileInfoListPtr listFileInfo(bool recursive = true, bool dirs = false); - - // Find functions will only work if vfs->hasFind is set. - Ogre::StringVectorPtr find(const Ogre::String& pattern, bool recursive = true, - bool dirs = false); - Ogre::FileInfoListPtr findFileInfo(const Ogre::String& pattern, - bool recursive = true, - bool dirs = false); -}; - -}} // namespaces -#endif diff --git a/libs/mangle/vfs/servers/ogre_vfs.cpp b/libs/mangle/vfs/servers/ogre_vfs.cpp deleted file mode 100644 index 7f728c1b0..000000000 --- a/libs/mangle/vfs/servers/ogre_vfs.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "ogre_vfs.hpp" -#include "../../stream/servers/ogre_datastream.hpp" - -using namespace Mangle::VFS; -using namespace Mangle::Stream; - -OgreVFS::OgreVFS(const std::string &_group) - : group(_group) -{ - hasList = true; - hasFind = true; - isCaseSensitive = true; - - // Get the group manager once - gm = Ogre::ResourceGroupManager::getSingletonPtr(); - - // Use the default group if none was specified - if(group.empty()) - group = gm->getWorldResourceGroupName(); -} - -StreamPtr OgreVFS::open(const std::string &name) -{ - Ogre::DataStreamPtr data = gm->openResource(name, group); - return StreamPtr(new OgreStream(data)); -} - -static void fill(FileInfoList &out, Ogre::FileInfoList &in, bool dirs) -{ - int size = in.size(); - out.resize(size); - - for(int i=0; ilistResourceFileInfo(group, dirs); - FileInfoListPtr res(new FileInfoList); - fill(*res, *olist, dirs); - return res; -} - -FileInfoListPtr OgreVFS::find(const std::string& pattern, - bool recursive, - bool dirs) const -{ - Ogre::FileInfoListPtr olist = gm->findResourceFileInfo(group, pattern, dirs); - FileInfoListPtr res(new FileInfoList); - fill(*res, *olist, dirs); - return res; -} diff --git a/libs/mangle/vfs/servers/ogre_vfs.hpp b/libs/mangle/vfs/servers/ogre_vfs.hpp deleted file mode 100644 index 7ab64169d..000000000 --- a/libs/mangle/vfs/servers/ogre_vfs.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef MANGLE_VFS_OGRESERVER_H -#define MANGLE_VFS_OGRESERVER_H - -#include "../vfs.hpp" -#include - -namespace Mangle { -namespace VFS { - -/** @brief An interface into the OGRE VFS system. - - This class does NOT wrap a single Ogre::Archive, but rather an - entire resource group in Ogre. You can use this class to tap into - all paths, Zip files, custom archives on so on that have been - inserted into Ogre as resource locations. - - This has been built and tested against OGRE 1.6.2. You might have - to make your own modifications if you're working with newer (or - older) versions. - */ -class OgreVFS : public VFS -{ - std::string group; - Ogre::ResourceGroupManager *gm; - - public: - /** @brief Constructor - - OGRE must be initialized (ie. you must have created an - Ogre::Root object somewhere) before calling this. - - @param group Optional resource group name. If none is given, - OGRE's default (or 'World') resource group is used. - */ - OgreVFS(const std::string &_group = ""); - - /// Open a new data stream. Deleting the object should be enough to - /// close it. - virtual Stream::StreamPtr open(const std::string &name); - - /// Check for the existence of a file - virtual bool isFile(const std::string &name) const - { return gm->resourceExists(group, name); } - - /// This doesn't work, always returns false. - virtual bool isDir(const std::string &name) const - { return false; } - - /// This doesn't work. - virtual FileInfoPtr stat(const std::string &name) const - { return FileInfoPtr(); } - - /// List all entries in a given directory. A blank dir should be - /// interpreted as a the root/current directory of the archive. If - /// dirs is true, list directories instead of files. OGRE note: The - /// ogre resource systemd does not support recursive listing of - /// files. We might make a separate filter for this later. - virtual FileInfoListPtr list(const std::string& dir = "", - bool recurse=true, - bool dirs=false) const; - - /// Find files after a given pattern. Wildcards (*) are - /// supported. - virtual FileInfoListPtr find(const std::string& pattern, - bool recursive=true, - bool dirs=false) const; -}; - -}} // namespaces -#endif diff --git a/libs/mangle/vfs/servers/physfs_vfs.hpp b/libs/mangle/vfs/servers/physfs_vfs.hpp deleted file mode 100644 index 8535088e0..000000000 --- a/libs/mangle/vfs/servers/physfs_vfs.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef MANGLE_VFS_PHYSFS_SERVER_H -#define MANGLE_VFS_PHYSFS_SERVER_H - -#include "../vfs.hpp" -#include "../../stream/servers/phys_stream.hpp" - -#include -#include - -namespace Mangle { -namespace VFS { - -/** @brief An interface into the PhysFS virtual file system library - - You have to set up PhysFS on your own before using this class. - */ -class PhysVFS : public VFS -{ - public: - PhysVFS() - { - hasList = true; - hasFind = false; - isCaseSensitive = true; - } - - /// Open a new data stream. Deleting the object should be enough to - /// close it. - virtual Stream::StreamPtr open(const std::string &name) - { return Stream::StreamPtr(new Stream::PhysFile(PHYSFS_openRead(name.c_str()))); } - - /// Check for the existence of a file - virtual bool isFile(const std::string &name) const - { return PHYSFS_exists(name.c_str()); } - - /// Checks for a directory - virtual bool isDir(const std::string &name) const - { return PHYSFS_isDirectory(name.c_str()); } - - /// This doesn't work - virtual FileInfoPtr stat(const std::string &name) const - { assert(0); return FileInfoPtr(); } - - virtual FileInfoListPtr list(const std::string& dir = "", - bool recurse=true, - bool dirs=false) const - { - char **files = PHYSFS_enumerateFiles(dir.c_str()); - FileInfoListPtr lst(new FileInfoList); - - // Add all teh files - int i = 0; - while(files[i] != NULL) - { - FileInfo fi; - fi.name = files[i]; - fi.isDir = false; - - lst->push_back(fi); - } - return lst; - } - - virtual FileInfoListPtr find(const std::string& pattern, - bool recursive=true, - bool dirs=false) const - { assert(0); } -}; - -}} // namespaces -#endif diff --git a/libs/mangle/vfs/tests/.gitignore b/libs/mangle/vfs/tests/.gitignore deleted file mode 100644 index 814490404..000000000 --- a/libs/mangle/vfs/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*_test diff --git a/libs/mangle/vfs/tests/Makefile b/libs/mangle/vfs/tests/Makefile deleted file mode 100644 index a5d1d1712..000000000 --- a/libs/mangle/vfs/tests/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -GCC=g++ -I../ -Wall - -all: dummy_test ogre_client_test ogre_resource_test ogre_server_test physfs_server_test - -I_OGRE=$(shell pkg-config --cflags OGRE) -L_OGRE=$(shell pkg-config --libs OGRE) -L_PHYSFS=-lphysfs - -ogre_client_test: ogre_client_test.cpp dummy_vfs.cpp ../vfs.hpp ../clients/ogre_archive.hpp ../clients/ogre_archive.cpp - $(GCC) $< ../clients/ogre_archive.cpp -o $@ $(I_OGRE) $(L_OGRE) - -ogre_resource_test: ogre_resource_test.cpp - $(GCC) $< -o $@ $(I_OGRE) $(L_OGRE) - -ogre_server_test: ogre_server_test.cpp ../vfs.hpp ../servers/ogre_vfs.hpp ../servers/ogre_vfs.cpp - $(GCC) $< -o $@ $(I_OGRE) $(L_OGRE) ../servers/ogre_vfs.cpp - -physfs_server_test: physfs_server_test.cpp ../vfs.hpp ../servers/physfs_vfs.hpp - $(GCC) $< -o $@ $(L_PHYSFS) - -dummy_test: dummy_test.cpp dummy_vfs.cpp ../vfs.hpp - $(GCC) $< -o $@ - -clean: - rm *_test diff --git a/libs/mangle/vfs/tests/dummy_test.cpp b/libs/mangle/vfs/tests/dummy_test.cpp deleted file mode 100644 index 541010c6a..000000000 --- a/libs/mangle/vfs/tests/dummy_test.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "dummy_vfs.cpp" - -#include -#include - -using namespace std; - -void print(FileInfo &inf) -{ - cout << "name: " << inf.name << endl; - cout << "basename: " << inf.basename << endl; - cout << "isDir: " << inf.isDir << endl; - cout << "size: " << inf.size << endl; - cout << "time: " << inf.time << endl; -} -void print(FileInfoPtr inf) { print(*inf); } - -void print(FileInfoList &lst) -{ - for(unsigned i=0; isize() << endl; - - return 0; -} diff --git a/libs/mangle/vfs/tests/dummy_vfs.cpp b/libs/mangle/vfs/tests/dummy_vfs.cpp deleted file mode 100644 index 0448e96a5..000000000 --- a/libs/mangle/vfs/tests/dummy_vfs.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// This file is shared between several test programs -#include "vfs.hpp" -#include -#include - -#include "../../stream/servers/memory_stream.hpp" - -using namespace Mangle::VFS; -using namespace Mangle::Stream; - -class DummyVFS : public VFS -{ -public: - DummyVFS() - { - hasFind = false; - hasList = true; - isCaseSensitive = true; - } - - // We only support opening 'file1' at the moment. - StreamPtr open(const std::string &name) - { - assert(name == "file1"); - return StreamPtr(new MemoryStream("hello world", 11)); - } - - bool isFile(const std::string &name) const - { - return (name == "file1" || - name == "dir/file2"); - } - - bool isDir(const std::string &name) const - { - return name == "dir"; - } - - /// Get info about a single file - FileInfoPtr stat(const std::string &name) const - { - FileInfoPtr fi(new FileInfo); - fi->name = name; - fi->time = 0; - - if(isFile(name)) - { - if(name == "dir/file2") - { - fi->basename = "file2"; - fi->size = 2; - } - else - { - fi->basename = "file1"; - fi->size = 1; - } - fi->isDir = false; - } - else if(isDir(name)) - { - fi->basename = "dir"; - fi->isDir = true; - fi->size = 0; - } - else assert(0); - - return fi; - } - - /// List all entries in a given directory. A blank dir should be - /// interpreted as a the root/current directory of the archive. If - /// dirs is true, list directories instead of files. - virtual FileInfoListPtr list(const std::string& dir = "", - bool recurse=true, - bool dirs=false) const - { - assert(dir == ""); - - FileInfoListPtr fl(new FileInfoList); - - FileInfo fi; - - if(!dirs) - { - fi.name = "file1"; - fi.basename = "file1"; - fi.isDir = false; - fi.size = 1; - fi.time = 0; - fl->push_back(fi); - - if(recurse) - { - fi.name = "dir/file2"; - fi.basename = "file2"; - fi.size = 2; - fl->push_back(fi); - } - } - else - { - fi.name = "dir"; - fi.basename = "dir"; - fi.isDir = true; - fi.size = 0; - fi.time = 0; - fl->push_back(fi); - } - return fl; - } - - FileInfoListPtr find(const std::string& pattern, - bool recursive=true, - bool dirs=false) const - { assert(0); } -}; diff --git a/libs/mangle/vfs/tests/ogre_client_test.cpp b/libs/mangle/vfs/tests/ogre_client_test.cpp deleted file mode 100644 index 8e1269b56..000000000 --- a/libs/mangle/vfs/tests/ogre_client_test.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "dummy_vfs.cpp" -#include "../clients/ogre_archive.hpp" -#include - -using namespace Ogre; -using namespace std; - -void print(StringVectorPtr lst) -{ - int s = lst->size(); - - for(int i=0; isize() << endl; - cout << "contents: " << file->getAsString() << endl; - - return 0; -} diff --git a/libs/mangle/vfs/tests/ogre_resource_test.cpp b/libs/mangle/vfs/tests/ogre_resource_test.cpp deleted file mode 100644 index 8965adaa1..000000000 --- a/libs/mangle/vfs/tests/ogre_resource_test.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include - -/* - This isn't really a test of our implementation, but a test of using - the Ogre resource system to find files. If the Ogre interface - changes and you have to change this test, you will have to change - the servers/ogre_vfs.cpp implementation equivalently. - - */ - -using namespace std; -using namespace Ogre; - -ResourceGroupManager *gm; -String group; - -void find(const std::string &fileName) -{ - cout << "\nFile: " << fileName << endl; - - if(!gm->resourceExists(group, fileName)) - { - cout << "Does not exist\n"; - return; - } - - DataStreamPtr data = gm->openResource(fileName, group); - - cout << "Size: " << data->size() << endl; - cout << "First line: " << data->getLine() << "\n"; -} - -int main() -{ - // Disable logging - new LogManager; - Log *log = LogManager::getSingleton().createLog(""); - log->setDebugOutputEnabled(false); - - // Set up Ogre - Root root("","",""); - - root.addResourceLocation("./", "FileSystem", "General"); - - gm = ResourceGroupManager::getSingletonPtr(); - group = gm->getWorldResourceGroupName(); - - find("Makefile"); - find("ogre_resource_test.cpp"); - find("bleh"); - - cout << "\nAll source files:\n"; - FileInfoListPtr list = gm->findResourceFileInfo(group, "*.cpp"); - FileInfoList::iterator it, end; - it = list->begin(); - end = list->end(); - for(; it != end; it++) - cout << " " << it->filename << endl; -} diff --git a/libs/mangle/vfs/tests/ogre_server_test.cpp b/libs/mangle/vfs/tests/ogre_server_test.cpp deleted file mode 100644 index b846eef96..000000000 --- a/libs/mangle/vfs/tests/ogre_server_test.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "../servers/ogre_vfs.hpp" - -#include - -#include "server_common.cpp" - -Ogre::Root *root; - -void setupOgre() -{ - using namespace Ogre; - - // Disable logging - new LogManager; - Log *log = LogManager::getSingleton().createLog(""); - log->setDebugOutputEnabled(false); - - // Set up Root - root = new Root("","",""); - - // Add a zip file and the current directory - root->addResourceLocation("test.zip", "Zip", "General"); - root->addResourceLocation("./", "FileSystem", "General"); -} - -int main() -{ - // Set up the engine - setupOgre(); - - // This is our entry point into the resource file system - OgreVFS vfs("General"); - - // Run the test - testAll(vfs); - - return 0; -} diff --git a/libs/mangle/vfs/tests/output/dummy_test.out b/libs/mangle/vfs/tests/output/dummy_test.out deleted file mode 100644 index 61f1fda80..000000000 --- a/libs/mangle/vfs/tests/output/dummy_test.out +++ /dev/null @@ -1,31 +0,0 @@ -Listing all files: -name: file1 -basename: file1 -isDir: 0 -size: 1 -time: 0 -name: dir/file2 -basename: file2 -isDir: 0 -size: 2 -time: 0 - -Stat for single files: -name: file1 -basename: file1 -isDir: 0 -size: 1 -time: 0 - -name: dir/file2 -basename: file2 -isDir: 0 -size: 2 -time: 0 - -name: dir -basename: dir -isDir: 1 -size: 0 -time: 0 -filesize: 11 diff --git a/libs/mangle/vfs/tests/output/ogre_client_test.out b/libs/mangle/vfs/tests/output/ogre_client_test.out deleted file mode 100644 index bc10b1e5c..000000000 --- a/libs/mangle/vfs/tests/output/ogre_client_test.out +++ /dev/null @@ -1,12 +0,0 @@ -Case: 1 -Name: dummy -Type: Mangle -All files: - file1 - dir/file2 -Non-recursive: - file1 -Dirs: - dir -filesize: 11 -contents: hello world diff --git a/libs/mangle/vfs/tests/output/ogre_resource_test.out b/libs/mangle/vfs/tests/output/ogre_resource_test.out deleted file mode 100644 index 9bfc4ff5b..000000000 --- a/libs/mangle/vfs/tests/output/ogre_resource_test.out +++ /dev/null @@ -1,20 +0,0 @@ - -File: Makefile -Size: 828 -First line: GCC=g++ -I../ - -File: ogre_resource_test.cpp -Size: 1437 -First line: #include - -File: bleh -Does not exist - -All source files: - physfs_server_test.cpp - dummy_test.cpp - ogre_resource_test.cpp - server_common.cpp - dummy_vfs.cpp - ogre_client_test.cpp - ogre_server_test.cpp diff --git a/libs/mangle/vfs/tests/output/ogre_server_test.out b/libs/mangle/vfs/tests/output/ogre_server_test.out deleted file mode 100644 index 74f350844..000000000 --- a/libs/mangle/vfs/tests/output/ogre_server_test.out +++ /dev/null @@ -1,11 +0,0 @@ - -File: Makefile -Size: 828 -First 12 bytes: GCC=g++ -I.. - -File: testfile.txt -Size: 13 -First 12 bytes: hello world! - -File: blah_bleh -File doesn't exist diff --git a/libs/mangle/vfs/tests/output/physfs_server_test.out b/libs/mangle/vfs/tests/output/physfs_server_test.out deleted file mode 100644 index 74f350844..000000000 --- a/libs/mangle/vfs/tests/output/physfs_server_test.out +++ /dev/null @@ -1,11 +0,0 @@ - -File: Makefile -Size: 828 -First 12 bytes: GCC=g++ -I.. - -File: testfile.txt -Size: 13 -First 12 bytes: hello world! - -File: blah_bleh -File doesn't exist diff --git a/libs/mangle/vfs/tests/physfs_server_test.cpp b/libs/mangle/vfs/tests/physfs_server_test.cpp deleted file mode 100644 index 9e9d088cd..000000000 --- a/libs/mangle/vfs/tests/physfs_server_test.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "../servers/physfs_vfs.hpp" - -#include "server_common.cpp" - -#include - -int main() -{ - // Set up the library and paths - PHYSFS_init("blah"); - PHYSFS_addToSearchPath("test.zip", 1); - PHYSFS_addToSearchPath("./", 1); - - // Create our interface - PhysVFS vfs; - - // Run the test - testAll(vfs); - - return 0; -} diff --git a/libs/mangle/vfs/tests/server_common.cpp b/libs/mangle/vfs/tests/server_common.cpp deleted file mode 100644 index 1834bc25a..000000000 --- a/libs/mangle/vfs/tests/server_common.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include - -using namespace Mangle::VFS; -using namespace Mangle::Stream; -using namespace std; - -void find(VFS &vfs, const std::string &file) -{ - cout << "\nFile: " << file << endl; - - if(!vfs.isFile(file)) - { - cout << "File doesn't exist\n"; - return; - } - - StreamPtr data = vfs.open(file); - - cout << "Size: " << data->size() << endl; - - char buf[13]; - buf[12] = 0; - data->read(buf, 12); - - cout << "First 12 bytes: " << buf << "\n"; -} - -void testAll(VFS &vfs) -{ - find(vfs, "Makefile"); // From the file system - find(vfs, "testfile.txt"); // From the zip - find(vfs, "blah_bleh"); // Doesn't exist -} diff --git a/libs/mangle/vfs/tests/test.sh b/libs/mangle/vfs/tests/test.sh deleted file mode 100755 index 2d07708ad..000000000 --- a/libs/mangle/vfs/tests/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -make || exit - -mkdir -p output - -PROGS=*_test - -for a in $PROGS; do - if [ -f "output/$a.out" ]; then - echo "Running $a:" - ./$a | diff output/$a.out - - else - echo "Creating $a.out" - ./$a > "output/$a.out" - git add "output/$a.out" - fi -done diff --git a/libs/mangle/vfs/tests/test.zip b/libs/mangle/vfs/tests/test.zip deleted file mode 100644 index ec82f8bc6..000000000 Binary files a/libs/mangle/vfs/tests/test.zip and /dev/null differ diff --git a/libs/mangle/vfs/vfs.hpp b/libs/mangle/vfs/vfs.hpp deleted file mode 100644 index 258a6b0a0..000000000 --- a/libs/mangle/vfs/vfs.hpp +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef MANGLE_VFS_H -#define MANGLE_VFS_H - -#include "../stream/stream.hpp" -#include -#include - -namespace Mangle { -namespace VFS { - -/// Generic file info structure -struct FileInfo -{ - /// Full name, including path - std::string name; - - /// Base name, not including path - std::string basename; - - /// Is this a directory? - bool isDir; - - /// File size - size_t size; - - /// Last modification date - time_t time; -}; - -typedef std::vector FileInfoList; - -typedef boost::shared_ptr FileInfoPtr; -typedef boost::shared_ptr FileInfoListPtr; - -/** An interface to any file system or other provider of named data - streams -*/ -class VFS -{ - public: - // Feature options. These should be set in the constructor. - - /// If true, the list() function work - bool hasList; - - /// If true, the find() function work - bool hasFind; - - /// If true, the file system is case sensitive - bool isCaseSensitive; - - /// Virtual destructor - virtual ~VFS() {} - - /// Open a new data stream. Deleting the object (letting all the - /// pointers to it go out of scope) should be enough to close it. - virtual Stream::StreamPtr open(const std::string &name) = 0; - - /// Check for the existence of a file - virtual bool isFile(const std::string &name) const = 0; - - /// Check for the existence of a directory - virtual bool isDir(const std::string &name) const = 0; - - /// Get info about a single file - virtual FileInfoPtr stat(const std::string &name) const = 0; - - /// List all entries in a given directory. A blank dir should be - /// interpreted as a the root/current directory of the archive. If - /// dirs is true, list directories instead of files. - virtual FileInfoListPtr list(const std::string& dir = "", - bool recurse=true, - bool dirs=false) const = 0; - - /// Find files after a given pattern. Wildcards (*) are - /// supported. Only valid if 'hasFind' is true. Don't implement your - /// own pattern matching here if the backend doesn't support it - /// natively; use a filter instead. - virtual FileInfoListPtr find(const std::string& pattern, - bool recursive=true, - bool dirs=false) const = 0; -}; - -typedef boost::shared_ptr VFSPtr; - -}} // namespaces -#endif diff --git a/libs/openengine/bullet/BtOgre.cpp b/libs/openengine/bullet/BtOgre.cpp index 618739083..f50465159 100644 --- a/libs/openengine/bullet/BtOgre.cpp +++ b/libs/openengine/bullet/BtOgre.cpp @@ -17,6 +17,10 @@ #include "BtOgreGP.h" #include "BtOgreExtras.h" +#include +#include +#include + using namespace Ogre; namespace BtOgre { diff --git a/libs/openengine/bullet/BtOgreGP.h b/libs/openengine/bullet/BtOgreGP.h index f0534de4b..4ce2f181e 100644 --- a/libs/openengine/bullet/BtOgreGP.h +++ b/libs/openengine/bullet/BtOgreGP.h @@ -19,7 +19,10 @@ #include "btBulletDynamicsCommon.h" #include "BtOgreExtras.h" -#include "Ogre.h" + +#include +#include +#include namespace BtOgre { diff --git a/libs/openengine/bullet/CMotionState.cpp b/libs/openengine/bullet/CMotionState.cpp index d7746cbc5..dc28d9e5f 100644 --- a/libs/openengine/bullet/CMotionState.cpp +++ b/libs/openengine/bullet/CMotionState.cpp @@ -4,7 +4,6 @@ #include #include #include -//#include namespace OEngine { namespace Physic diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 1bc4341a0..a778aef3a 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -3,7 +3,6 @@ #include #include #include -//#include #include "CMotionState.h" #include "OgreRoot.h" #include "btKinematicCharacterController.h" @@ -12,6 +11,7 @@ #include "BtOgreExtras.h" #include +#include #define BIT(x) (1<<(x)) @@ -286,7 +286,7 @@ namespace Physic minh = h; maxh = h; } - + if (h>maxh) maxh = h; if (hload(mesh,"General"); - BulletShapeManager::getSingletonPtr()->load(mesh,"General"); - BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(mesh,"General"); - shape->Shape->setLocalScaling(btVector3(scale,scale,scale)); + mShapeLoader->load(outputstring,"General"); + BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); + BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); + shape->Shape->setLocalScaling( btVector3(scale,scale,scale)); + //btScaledBvhTriangleMeshShape* scaled = new btScaledBvhTriangleMeshShape(dynamic_cast (shape->Shape), btVector3(scale,scale,scale)); //create the motionState CMotionState* newMotionState = new CMotionState(this,name); @@ -401,18 +406,32 @@ namespace Physic if (it != RigidBodyMap.end() ) { RigidBody* body = it->second; + //btScaledBvhTriangleMeshShape* scaled = dynamic_cast (body->getCollisionShape()); + if(body != NULL) { delete body; } + /*if(scaled != NULL) + { + delete scaled; + }*/ RigidBodyMap.erase(it); } } RigidBody* PhysicEngine::getRigidBody(std::string name) { - RigidBody* body = RigidBodyMap[name]; - return body; + RigidBodyContainer::iterator it = RigidBodyMap.find(name); + if (it != RigidBodyMap.end() ) + { + RigidBody* body = RigidBodyMap[name]; + return body; + } + else + { + return 0; + } } void PhysicEngine::stepSimulation(double deltaT) @@ -469,8 +488,16 @@ namespace Physic PhysicActor* PhysicEngine::getCharacter(std::string name) { - PhysicActor* act = PhysicActorMap[name]; - return act; + PhysicActorContainer::iterator it = PhysicActorMap.find(name); + if (it != PhysicActorMap.end() ) + { + PhysicActor* act = PhysicActorMap[name]; + return act; + } + else + { + return 0; + } } void PhysicEngine::emptyEventLists(void) @@ -540,4 +567,20 @@ namespace Physic return results2; } + + void PhysicEngine::getObjectAABB(const std::string &mesh, float scale, btVector3 &min, btVector3 &max) + { + std::string sid = (boost::format("%07.3f") % scale).str(); + std::string outputstring = mesh + sid; + + mShapeLoader->load(outputstring, "General"); + BulletShapeManager::getSingletonPtr()->load(outputstring, "General"); + BulletShapePtr shape = + BulletShapeManager::getSingleton().getByName(outputstring, "General"); + + btTransform trans; + trans.setIdentity(); + + shape->Shape->getAabb(trans, min, max); + } }}; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index e327f24e1..9ae8e7607 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -7,6 +7,7 @@ #include #include #include "BulletShapeLoader.h" +#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" class btRigidBody; class btBroadphaseInterface; @@ -220,6 +221,8 @@ namespace Physic bool toggleDebugRendering(); + void getObjectAABB(const std::string &mesh, float scale, btVector3 &min, btVector3 &max); + /** * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). */ diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index b723f67e4..e13e9e6c0 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -229,7 +229,7 @@ bool PM_SlideMove( bool gravity ) end = pm->ps.origin + pm->ps.velocity * time_left; // see if we can make it there - //pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask); + //pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemaskg); //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&(end), *(const D3DXVECTOR3* const)&(pm->ps.velocity), 0, pml.traceObj); newtrace(&trace, pm->ps.origin, end, halfExtents, Ogre::Math::DegreesToRadians (pm->ps.viewangles.y), pm->isInterior, pm->mEngine); @@ -274,7 +274,7 @@ bool PM_SlideMove( bool gravity ) { // pm->ps->velocity += (trace.plane.normal + pm->ps->velocity) //VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); - pm->ps.velocity = (trace.planenormal + pm->ps.velocity); + pm->ps.velocity = trace.planenormal + pm->ps.velocity; break; } } @@ -298,6 +298,12 @@ bool PM_SlideMove( bool gravity ) if ( into >= 0.1 ) continue; // move doesn't interact with the plane + + if(planes[i].x >= .70) + { + pm->ps.velocity = Ogre::Vector3(0,0,0); + return true; + } // see how hard we are hitting things if ( -into > pml.impactSpeed ) pml.impactSpeed = -into; @@ -318,6 +324,13 @@ bool PM_SlideMove( bool gravity ) if (clipVelocity.dotProduct(planes[j]) >= 0.1) //if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) continue; // move doesn't interact with the plane + + + + + //pm->ps.velocity = Ogre::Vector3(0,0,0); + //return true; + // try clipping the move to the plane PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); @@ -327,8 +340,8 @@ bool PM_SlideMove( bool gravity ) if (clipVelocity.dotProduct(planes[i]) >= 0) //if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) continue; - - + + // slide the original velocity along the crease //dProduct (planes[i], planes[j], dir); dir = planes[i].crossProduct(planes[j]) ; @@ -360,6 +373,7 @@ bool PM_SlideMove( bool gravity ) // see if there is a third plane the the new move enters for ( k = 0 ; k < numplanes ; k++ ) { + if ( k == i || k == j ) continue; @@ -513,7 +527,7 @@ int PM_StepSlideMove( bool gravity ) delta = pm->ps.origin.z - start_o.z; if ( delta > 2 ) { - pm->ps.counter = 10; + pm->ps.counter = 5; /* if (gravity) @@ -844,6 +858,8 @@ static void PM_WalkMove( playerMove* const pmove ) float accelerate; float vel; //pm->ps.gravity = 4000; + + //std::cout << "Player is walking\n"; if ( pm->ps.waterlevel > 2 && //DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) pml.forward.dotProduct(pml.groundTrace.planenormal) > 0.0f) @@ -1145,6 +1161,10 @@ void PM_GroundTraceMissed() { traceResults trace; Ogre::Vector3 point; + //We should not have significant upwards velocity when in the air, unless we jumped. + //This code protects against flying into the air when moving at high speeds. + //Z velocity is set to 50, instead of 0, to help move up certain steps. + //std::cout << "Ground trace missed\n"; // we just transitioned into freefall //if ( pm->debugLevel ) @@ -1407,10 +1427,13 @@ static void PM_GroundTrace( void ) // if the trace didn't hit anything, we are in free fall if ( trace.fraction == 1.0) { + if(pm->ps.velocity.z > 50.0f && pm->ps.bSnap && pm->ps.speed > 1000.0f) + pm->ps.velocity.z = 50.0f; if(pm->ps.snappingImplemented){ if(pm->ps.bSnap && pm->ps.counter <= 0) PM_GroundTraceMissed(); } + return; @@ -1457,6 +1480,7 @@ static void PM_GroundTrace( void ) // slopes that are too steep will not be considered onground //if ( trace.plane.normal[2] < MIN_WALK_NORMAL ) + //std::cout << "MinWalkNormal" << trace.planenormal.z; if (trace.planenormal.z < MIN_WALK_NORMAL) { //if ( pm->debugLevel ) @@ -1569,8 +1593,11 @@ void PM_AirMove() else PM_SlideMove ( qtrue ); #endif*/ + //std::cout << "Moving in the air" << pm->ps.velocity << "\n"; /*bprintf("%i ", */PM_StepSlideMove ( true )/* )*/; + + } static void PM_NoclipMove( void ) diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index 6cedd3599..aea63d1db 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -6,12 +6,12 @@ which was released under the GNU GPL (v2) in 2005. Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. */ -#include #include #include #include "trace.h" #include "physic.hpp" +#include //#include "GameMath.h" //#include "GameTime.h" @@ -28,7 +28,7 @@ static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2); #define MAX_CLIP_PLANES 5 #define OVERCLIP 1.001f //#define STEPSIZE 18 // 18 is way too much -#define STEPSIZE (18 / 2) +#define STEPSIZE (9) #ifndef M_PI #define M_PI 3.14159265358979323846f #endif @@ -41,7 +41,7 @@ static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2); #define MAX_GENTITIES (1 << GENTITYNUM_BITS) #define ENTITYNUM_NONE (MAX_GENTITIES - 1) #define ENTITYNUM_WORLD (MAX_GENTITIES - 2) -#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes +#define MIN_WALK_NORMAL .7f // can't walk on very steep slopes #define JUMP_VELOCITY (270) #define PS_PMOVEFRAMECOUNTBITS 6 #define MINS_Z -24 @@ -154,7 +154,7 @@ struct playerMove KEYUP }; - playercmd() : forwardmove(0), rightmove(0), upmove(0), serverTime(50), ducking(false), + playercmd() : forwardmove(0), rightmove(0), upmove(0), serverTime(50), ducking(false), activating(false), lastActivatingState(false), procActivating(NO_CHANGE), dropping(false), lastDroppingState(false), procDropping(NO_CHANGE) { diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index d446b6854..076baf56e 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -5,12 +5,11 @@ #include #include #include -//#include #include #include - + enum traceWorldType { collisionWorldTrace = 1, @@ -33,7 +32,7 @@ struct NewPhysTraceResults float fraction; bool startSolid; //const Object* hitObj; -}; +}; struct traceResults { Ogre::Vector3 endpos; diff --git a/libs/openengine/gui/events.cpp b/libs/openengine/gui/events.cpp index bce70704b..35b01158b 100644 --- a/libs/openengine/gui/events.cpp +++ b/libs/openengine/gui/events.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include "events.hpp" diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index e6feb3d0e..9040dfb90 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -1,7 +1,6 @@ #ifndef OENGINE_MYGUI_LAYOUT_H #define OENGINE_MYGUI_LAYOUT_H -#include #include namespace OEngine { diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 022c5efb5..58929ba8b 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include "manager.hpp" @@ -36,6 +36,7 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::shutdown() { + mGui->shutdown (); delete mGui; if(mPlatform) { diff --git a/libs/openengine/input/dispatch_map.hpp b/libs/openengine/input/dispatch_map.hpp index f0d4cabe9..be13e7f01 100644 --- a/libs/openengine/input/dispatch_map.hpp +++ b/libs/openengine/input/dispatch_map.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace OEngine { namespace Input { diff --git a/libs/openengine/input/func_binder.hpp b/libs/openengine/input/func_binder.hpp index 7aa733edf..a815ba0ce 100644 --- a/libs/openengine/input/func_binder.hpp +++ b/libs/openengine/input/func_binder.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include namespace OEngine { namespace Input { diff --git a/libs/openengine/misc/list.hpp b/libs/openengine/misc/list.hpp index b08b57494..bda9cb8de 100644 --- a/libs/openengine/misc/list.hpp +++ b/libs/openengine/misc/list.hpp @@ -1,7 +1,7 @@ #ifndef MISC_LIST_H #define MISC_LIST_H -#include +#include namespace Misc{ diff --git a/libs/openengine/ogre/exitlistener.hpp b/libs/openengine/ogre/exitlistener.hpp deleted file mode 100644 index 5a9d1ff68..000000000 --- a/libs/openengine/ogre/exitlistener.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef OENGINE_OGRE_EXITLISTEN_H -#define OENGINE_OGRE_EXITLISTEN_H - -/* - This FrameListener simply exits the rendering loop when the window - is closed. You can also tell it to exit manually by setting the exit - member to true; - */ - -#include -#include - -namespace OEngine { -namespace Render -{ - struct ExitListener : Ogre::FrameListener - { - Ogre::RenderWindow *window; - bool exit; - - ExitListener(Ogre::RenderWindow *wnd) - : window(wnd), exit(false) {} - - bool frameStarted(const Ogre::FrameEvent &evt) - { - if(window->isClosed()) - exit = true; - - return !exit; - } - - // Function equivalent of setting exit=true. Handy when you need a - // delegate to bind to an event. - void exitNow() { exit = true; } - }; -}} -#endif diff --git a/libs/openengine/ogre/fader.cpp b/libs/openengine/ogre/fader.cpp index 062559e00..41b7773ea 100644 --- a/libs/openengine/ogre/fader.cpp +++ b/libs/openengine/ogre/fader.cpp @@ -8,8 +8,6 @@ #include #include -#include - #define FADE_OVERLAY_NAME "FadeInOutOverlay" #define FADE_OVERLAY_PANEL_NAME "FadeInOutOverlayPanel" #define FADE_MATERIAL_NAME "FadeInOutMaterial" diff --git a/libs/openengine/ogre/fader.hpp b/libs/openengine/ogre/fader.hpp index f76ac51ef..efb12a5d2 100644 --- a/libs/openengine/ogre/fader.hpp +++ b/libs/openengine/ogre/fader.hpp @@ -9,8 +9,6 @@ inspired by http://www.ogre3d.org/tikiwiki/FadeEffectOverlay (heavily adjusted) */ -#include - namespace Ogre { class TextureUnitState; diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 7c0f88bd7..e342f4c5f 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -9,12 +9,36 @@ #include "OgreTexture.h" #include "OgreHardwarePixelBuffer.h" -#include +#include + +#include + +#include +#include #include +#if defined(__APPLE__) && !defined(__LP64__) +#include +#endif + using namespace Ogre; using namespace OEngine::Render; +#if defined(__APPLE__) && !defined(__LP64__) + +CustomRoot::CustomRoot(const Ogre::String& pluginFileName, + const Ogre::String& configFileName, + const Ogre::String& logFileName) +: Ogre::Root(pluginFileName, configFileName, logFileName) +{} + +bool CustomRoot::isQueuedEnd() const +{ + return mQueuedEnd; +} + +#endif + void OgreRenderer::cleanup() { delete mFader; @@ -26,7 +50,32 @@ void OgreRenderer::cleanup() void OgreRenderer::start() { +#if defined(__APPLE__) && !defined(__LP64__) + // OSX Carbon Message Pump + 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; + } + + } while (!mRoot->isQueuedEnd()); +#else mRoot->startRendering(); +#endif } bool OgreRenderer::loadPlugins() const @@ -70,7 +119,6 @@ float OgreRenderer::getFPS() } void OgreRenderer::configure(const std::string &logPath, - const std::string &pluginCfg, const std::string& renderSystem, bool _logging) { @@ -86,13 +134,41 @@ void OgreRenderer::configure(const std::string &logPath, // Disable logging log->setDebugOutputEnabled(false); - #if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9) || defined(ENABLE_PLUGIN_CgProgramManager) || defined(ENABLE_PLUGIN_OctreeSceneManager) || defined(ENABLE_PLUGIN_ParticleFX) +#if defined(__APPLE__) && !defined(__LP64__) + mRoot = new CustomRoot("", "", ""); +#else mRoot = new Root("", "", ""); +#endif + + #if defined(ENABLE_PLUGIN_GL) || defined(ENABLE_PLUGIN_Direct3D9) || defined(ENABLE_PLUGIN_CgProgramManager) || defined(ENABLE_PLUGIN_OctreeSceneManager) || defined(ENABLE_PLUGIN_ParticleFX) loadPlugins(); - #else - mRoot = new Root(pluginCfg, "", ""); #endif + std::string pluginDir; + const char* pluginEnv = getenv("OPENMW_OGRE_PLUGIN_DIR"); + if (pluginEnv) + pluginDir = pluginEnv; + else + { +#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + pluginDir = ".\\"; +#endif +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + pluginDir = OGRE_PLUGIN_DIR; +#endif +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX + pluginDir = OGRE_PLUGIN_DIR_REL; +#endif + } + + boost::filesystem::path absPluginPath = boost::filesystem::absolute(boost::filesystem::path(pluginDir)); + + pluginDir = absPluginPath.string(); + + Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot); + Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); + Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); + RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded"); @@ -113,8 +189,8 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& // create the semi-transparent black background texture used by the GUI. // has to be created in code with TU_DYNAMIC_WRITE_ONLY_DISCARDABLE param - // so that it can be modified at runtime. - mTransparentBGTexture = Ogre::TextureManager::getSingleton().createManual( + // so that it can be modified at runtime. + Ogre::TextureManager::getSingleton().createManual( "transparent.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index f1520a3db..9b7003368 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -27,9 +27,15 @@ #include "OgreTexture.h" #include +#if defined(__APPLE__) && !defined(__LP64__) +#include +#endif + namespace Ogre { +#if !defined(__APPLE__) || defined(__LP64__) class Root; +#endif class RenderWindow; class SceneManager; class Camera; @@ -48,10 +54,25 @@ namespace OEngine std::string fsaa; }; +#if defined(__APPLE__) && !defined(__LP64__) + class CustomRoot : public Ogre::Root { + public: + bool isQueuedEnd() const; + + CustomRoot(const Ogre::String& pluginFileName = "plugins.cfg", + const Ogre::String& configFileName = "ogre.cfg", + const Ogre::String& logFileName = "Ogre.log"); + }; +#endif + class Fader; class OgreRenderer { +#if defined(__APPLE__) && !defined(__LP64__) + CustomRoot *mRoot; +#else Ogre::Root *mRoot; +#endif Ogre::RenderWindow *mWindow; Ogre::SceneManager *mScene; Ogre::Camera *mCamera; @@ -74,8 +95,6 @@ namespace OEngine Fader* mFader; bool logging; - Ogre::TexturePtr mTransparentBGTexture; - public: OgreRenderer() : mRoot(NULL) @@ -112,7 +131,6 @@ namespace OEngine set up the Root and logging classes. */ void configure( const std::string &logPath, // Path to directory where to store log files - const std::string &pluginCfg, // plugin.cfg file const std::string &renderSystem, bool _logging); // Enable or disable logging diff --git a/readme.txt b/readme.txt index 4cc31343b..ce3d115e3 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.15.0 +Version: 0.16.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -12,8 +12,6 @@ EBGaramond-Regular.ttf: OFL (see OFL.txt for more information) VeraMono.ttf: custom (see Bitstream Vera License.txt for more information) -THIS IS A WORK IN PROGRESS - INSTALLATION @@ -68,9 +66,16 @@ Allowed options: --debug [=arg(=1)] (=0) debug mode --nosound [=arg(=1)] (=0) disable all sounds --script-verbose [=arg(=1)] (=0) verbose script output - --new-game [=arg(=1)] (=0) activate char gen/new game mechanics --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scri pts) at startup + --script-console [=arg(=1)] (=0) enable console-only script functionality + --script-run arg select a file that is executed in the consol + e on startup + + Note: The file contains a list of script + lines, but not a complete scripts. That mean + s no begin/end and no variable declarations. + --new-game [=arg(=1)] (=0) activate char gen/new game mechanics --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding ) --encoding arg (=win1252) Character encoding used in OpenMW game messa @@ -90,49 +95,35 @@ Allowed options: --fallback arg fallback values -CREDITS - -Current Developers: -Aleksandar Jovanov -Alexander “Ace” Olofsson -athile -BrotherBrick -Cris “Mirceam” Mihalache -gugus / gus -Jacob “Yacoby” Essex -Jannik “scrawl” Heller -Jason “jhooks” Hooks -Karl-Felix “k1ll” Glatzer -Lukasz “lgro” Gromanowski -Marc “Zini” Zinnschlag -Michael “werdanith” Papageorgiou -Nikolay “corristo” Kasyanov -Pieter “pvdk” van der Kloet -Roman "Kromgart" Melnik -Sebastian “swick” Wick -Sylvain "Garvek" T. - -Retired Developers: -Ardekantur -Armin Preiml -Diggory Hardy -Jan Borsodi -Jan-Peter “peppe” Nilsson -Josua Grawitter -Nicolay Korslund -sergoz -Star-Demon -Yuri Krupenin - -OpenMW: -Thanks to DokterDume for kindly providing us with the Moon and Star logo used as the application icon and project logo. - -Launcher: -Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Files tab. - - CHANGELOG +0.16.0 + +Bug #250: OpenMW launcher erratic behaviour +Bug #270: Crash because of underwater effect on OS X +Bug #277: Auto-equipping in some cells not working +Bug #294: Container GUI ignores disabled inventory menu +Bug #297: Stats review dialog shows all skills and attribute values as 0 +Bug #298: MechanicsManager::buildPlayer does not remove previous bonuses +Bug #299: Crash in World::disable +Bug #306: Non-existent ~/.config/openmw "crash" the launcher. +Bug #307: False "Data Files" location make the launcher "crash" +Feature #81: Spell Window +Feature #85: Alchemy Window +Feature #181: Support for x.y script syntax +Feature #242: Weapon and Spell icons +Feature #254: Ingame settings window +Feature #293: Allow "stacking" game modes +Feature #295: Class creation dialog tooltips +Feature #296: Clicking on the HUD elements should show/hide the respective window +Feature #301: Direction after using a Teleport Door +Feature #303: Allow object selection in the console +Feature #305: Allow the use of = as a synonym for == +Feature #312: Compensation for slow object access in poorly written Morrowind.esm scripts +Task #176: Restructure enabling/disabling of MW-references +Task #283: Integrate ogre.cfg file in settings file +Task #290: Auto-Close MW-reference related GUI windows + 0.15.0 Bug #5: Physics reimplementation (fixes various issues) @@ -188,7 +179,6 @@ Task #113: Morrowind.ini Importer Task #215: Refactor the sound code Task #216: Update MyGUI - 0.13.0 Bug #145: Fixed sound problems after cell change @@ -246,7 +236,6 @@ Task #131: NPC Activation doesn't work properly Task #144: MWRender cleanup Task #155: cmake cleanup - 0.11.1 Bug #2: Resources loading doesn't work outside of bsa files @@ -273,4 +262,95 @@ Task #14: Replace tabs with 4 spaces Task #18: Move components from global namespace into their own namespace Task #123: refactor header files in components/esm -TODO add old changelog (take pre 0.11.1 changelog from wiki) +0.10.0 + +* NPC dialogue window (not functional yet) +* Collisions with objects +* Refactor the PlayerPos class +* Adjust file locations +* CMake files and test linking for Bullet +* Replace Ogre raycasting test for activation with something more precise +* Adjust player movement according to collision results +* FPS display +* Various Portability Improvements +* Mac OS X support is back! + +0.9.0 + +* Exterior cells loading, unloading and management +* Character Creation GUI +* Character creation +* Make cell names case insensitive when doing internal lookups +* Music player +* NPCs rendering + +0.8.0 + +* GUI +* Complete and working script engine +* In game console +* Sky rendering +* Sound and music +* Tons of smaller stuff + +0.7.0 + +* This release is a complete rewrite in C++. +* All D code has been culled, and all modules have been rewritten. +* The game is now back up to the level of rendering interior cells and moving around, but physics, sound, GUI, and scripting still remain to be ported from the old codebase. + +0.6.0 + +* Coded a GUI system using MyGUI +* Skinned MyGUI to look like Morrowind (work in progress) +* Integrated the Monster script engine +* Rewrote some functions into script code +* Very early MyGUI < > Monster binding +* Fixed Windows sound problems (replaced old openal32.dll) + +0.5.0 + +* Collision detection with Bullet +* Experimental walk & fall character physics +* New key bindings: + * t toggle physics mode (walking, flying, ghost), + * n night eye, brightens the scene +* Fixed incompatability with DMD 1.032 and newer compilers +* * (thanks to tomqyp) +* Various minor changes and updates + +0.4.0 + +* Switched from Audiere to OpenAL +* * (BIG thanks to Chris Robinson) +* Added complete Makefile (again) as a alternative build tool +* More realistic lighting (thanks again to Chris Robinson) +* Various localization fixes tested with Russian and French versions +* Temporary workaround for the Unicode issue: invalid UTF displayed as '?' +* Added ns option to disable sound, for debugging +* Various bug fixes +* Cosmetic changes to placate gdc Wall + +0.3.0 + +* Built and tested on Windows XP +* Partial support for FreeBSD (exceptions do not work) +* You no longer have to download Monster separately +* Made an alternative for building without DSSS (but DSSS still works) +* Renamed main program from 'morro' to 'openmw' +* Made the config system more robust +* Added oc switch for showing Ogre config window on startup +* Removed some config files, these are auto generated when missing. +* Separated plugins.cfg into linux and windows versions. +* Updated Makefile and sources for increased portability +* confirmed to work against OIS 1.0.0 (Ubuntu repository package) + +0.2.0 + +* Compiles with gdc +* Switched to DSSS for building D code +* Includes the program esmtool + +0.1.0 + +first release